From 37b5992b0efc1e18e506f3a31ff2074cfd12b542 Mon Sep 17 00:00:00 2001 From: admin Date: Wed, 15 Jul 2026 07:09:21 +0000 Subject: [PATCH] Part Request submitter: clear 'NOT SIGNED IN' / form-not-loaded error instead of raw Selenium timeout --- assets/CHANGELOG.xlsx | Bin 5657 -> 5658 bytes scripts/altium365_part_request.py | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/assets/CHANGELOG.xlsx b/assets/CHANGELOG.xlsx index ad4994cd3f46c1c0c77f544537057301ee9c372b..8a57bcd27bfe338f678349e31651bfd102ccd0ec 100644 GIT binary patch delta 2248 zcmZ9OXHXLg62}7sj7l|xUPOw3v_L|UA{|0eBvRxMM7k6OM3iDMi9j&41f{Dq0TDt6 z>7fLWB1MW6K?pplp(;KIJb5#B_wM$~&TnUTKkUqZ_Maw~F2`zR&IIHJ001C>tVR+m z86>MgbA$>G`zDQELb+fHSD8CbOGwB*tuw;a8o~UM`KrUhCM$x^KLW&;ABP{weSqnu zDa<3+7>xr{6 zzBYX~8}B$}E_m=(OsxkwI$@$u$p;{~J7LY3boTZr3@Q|bdW%)Ljpj0b-F(K2cixc> z)(nXhCK?2qzoQ*ADlSdeVIs%7qW^e2(^rjq;B)`*MP`mcE1Ra}6B&QnN|-G|!H(bA z6FrVDHZO`@t?k*1p1nB{GUhjPtknGOm&2BzWT)B!@wQDHsi9DZ;h%S)Ii@*gigQ*T zF{rcreGnCbmM2jMB#l~8<%~LxrP%ebc2M{T%B>dr-LNd;OO2{b9~VV?qndCD4eZgM zrM~TXI9(YvoaE{)(pMAF-usHwtNDQRMt3bcamCSkzWwG{WOrdbn3=loA?{`jS6v*l zdj?Fuk%K>Q;oPO;E2afGikqJaaTpb8^ty=QWGnF>+ktfxsD#G&khT4Rnj%%#Zvx^f!Wa_-S9Sp1qLrV~7ALRLV)N?%fd~ zLc0coS+I6djpI}4ws$%%xEI$&VjkRBwnC!hxp zZg~~vK8?S7S;VaT;xL}#wUiy$BBi};?>{zYjWQ4KwJPY6MrV_t1n+}@+;m4<`eW%x zNuHVA3jYtTnM8xd%vFY3XqT%QR7(T3 z&DTBa?j+3XCqD`Mmr6IBY>@1$YZhfSz67eiu8}c+5i|qFZls7kKP&>Hhr`9+G zfzcn?zX=RAu40uk&NV)awIBwz8E)JR`$vB>iQ?N(Nr{uM&5LdVYOh z9WcSnk(V09J9dUw8V%e-js%9Z0xzSSW3){PO8NGB{WiPa+eq#s8Y7(SDgYxFFSLCd)f`%-i-vwvR1J;i{M177-4&A6Z1OSOc}4uX zGoLSCUjH~Bqz~b|6ezy+6%qfy!L8q@(e>Alx=IJb^|W~8NOjU?C00wPN&t=OKCWR& z_mRU*i~&khOr;0}%!?w|K!vw-@W>HwnsMHU@B=16q)E(j?`O*A>ZK#aLUC5_$TDX?DisPnM0E z5JT!2W#c8qPaIj_*T}X*`AzOFsr$M`agYh5@q5}F#!N}JVYof56VA7iSr4hg9$I; zC1)XK-OKGgtZL(cS|c$@*(;~=k0j~P!&Sxd_H35(%%*^aZOsj|jfNeKIe&*>>TVdK zX#3CDaliQ#Gq@<`O~08#(vK`JuM+sPM9B3}Sq{A^Q?qRzT?mKmb0h8>*wLeh$dJ)e z>yi{)sV%N$6SMvn#kqI0V!K2)gAg0afxY;|Onu7S!xz!HKNM?sz8lCpj7&dcc_?W* zX;SPo$zLXPc;h|KIqcK8P5n&zoa-GwkrHF*fJuG!J?1G(gXElwugf?x-#3*PYIs^g z+)`K~wa&5WCyAvBT`8n5Voj{oS_|gltsN@hQ1e;vU=+?mrAK=-^C}l?=X|!Unz`>F z&6cue)rQ2e#GX$+_d^_&HqYq#9MxaNO#W(A z?2eh(m)v+3P1zAf*$CQGv(5?}(CjlWNwIBe5Nk`fLxi?ScyD--Nxt_<+t87uyQ0g1t(P@O7u8 zCLOr*{`e0KdDE^@dZESP&i-JAxKTu{+fU~O1L*{yR? z0c&HC1O4Y&p=@i$juB8_k z6LYv0PB8kM+21$<*7}cIAo6mnowQhSU-|FDOySmHKd}@45ZeN`yy!_OCALAR^|$K) zGXel-f9HQkB!f9o5h8H1${ZrZ03&)qL{1>)H>42rAu=a0_#48B>kugx3ixF3FLsG3 AUjP6A delta 2247 zcmY+GdpOgN7sof|5_8#RiRPN*TA?H%Nv=b==WcQtlN2KKkz6veX64#9@y(=*nM+K< z#E>=$Q?Yz=%k5|8{-yNe`#itjuiyFSJg@VdbN)Eb^M1~|P^&--dft{FA_W40gh7qE zL?~UjQJ3o#L#8Vc2Q`6+;Srf3U(|F$*Vk$T=S&wtrx@GIf7eXB zg9J9->7|P9>-KMyP3Tt*Y%Ba%MlzpO5W%NB0bLt#ZTK7oo4}BRgqy60pSkLjZ28fZ zl(r{7HMMK@oot|T=7VWe{cQ)>$mZ01DU%1h+yCWSJyN_Z@Dh zZ61kP0G(1zpU8C{U61p9Pm2@+M>r6UEH@T}A!gWrZD^i6m!1?BQ~1MUgcBj}u1(X@ zyGh#94D<4~bs1@PsBHPcYHO~!Ja_nQY~8oA9J7}b65}L4Z+h|Tr!Ao0@4)pc@OpSa zvSu4>Ao$NgfYfL$l8LYyFs3h+_6yH&>xQ;7_UQ*E6)Y05hDEs-V?KxZD^%feaR*PP zY;VecPP0bba=Z+;WydG1m~0wA*Uc83MILvDF|Hk7a(tP2i~HOlHS5`_3#Qo-`es4S z0Zx|_U928kAAHxKAb4i9SFPs_uWHt_i+BEhVGU|;&Qsl&ExrP-oZa3|() zM>;+Fp6b(rF^Z}$z&$2M8W{c_FhzJkneH#t$QRir9W<1STbH-?J8N6nlJS$<7dxoO z!_Zw;^XBKMawt@uNDa0<{|sYk^K@dk(M?TZmT;SeWV5t+Foa{#mw05l7-oJ~@y4O) zV%v%#;b#?Ft0S7@LC*cW^LS%o&@l@=i3eN9XNa9wYXtKEk1@|QLt_gVH1RGGJxtg? zI8i;jRRYR&kLvGfoXn22cU5G2f#NibbqZ}j~i_`k{2ol3{ z5SDi+H7z(vl*Xx)F!SX~L>ta#@r$~RoeyLvw(Kt&DldnT{x0?*cuSF#^Xkn*)boK&^sD%2dY5 zKEjiG1fvBg*__FcPTfmY6BUm+pN;KJQhR&aYI$ znDO>E95TPZYM-4-RTg$JebIHdJ^s+ik67YyXlhtd`XsQf4xr(hn7%k^Rub zy=3Ui>T)1E)vUs+pH*-~+%{URf;eE3w)E2Ulz z9o^qB{1ryj?Aljw`ZVWy>5%7s`_3ju*4WCZ)b*)gy50lNT+KFWA0uabL9`NaG4E|O zzvkw%w2C?2tWL*s6pge*D5=;v3NU!wo7@8U-|mLNX}RE;F*K=%Tn!$&1= zBEJdclk#aiE52|GzpA@tTLA#lGX_#U*=_TEWu}~j>cmDX$wArvMVOg|=GR>N@=vp+ zAB5=gF4N z;jaBGk)|Gf){#b8(anc^3k8ThvnmAw_I_w=cNYTL<7X!@s&P3S+ucFW2v)QzyN3@s zo2q?V-KsFS{86J!)%=h9O*tYdC7D;0Sg)3Ks$LNoj~gV7Icisu2TREwdM@Gb+c7T| zAK;_LJI{u1?8VEIYY6ngBny#8XSy)q%dQ=4smQC+Kr`(R&lCJ1TwuTiy8O~v#woZg zrgYG(%4>haScmu{5B7OTMV%H?alG~(vMxgoc2Wt>Y(~>X!And;GqZAL7=OTt84Atu0=kEbY?mwd5w` zr9BO^jB(@zBgA5yLm_B^i41jS|1F5kz*NMMw$YM3FE@RxbA0h^!i&MqQ3~*gXLVKO zWDd$YTg5WxK=-<}?tF8IP%$%Df%)cs>#Z=Eg!JW7gH+()u(5QZ8wb}}ljTBb{^M@E zUHz2ljj7R3!CK|7sc$HIePgTB`6y+rN$^pD6D%!HMoh! z90thN0Q_8JmP^!|HC^|B=*)nP<@mP^V7^R#;#b$OggTx$ZA9o(q0g+OmQxdgispIT zX84{kRmlMAs0K-`uHZSjJ6r<4@nokt?1ctHY?$7lYJF5}rL@Izd|!nr&T@`j(Y z9vezx^(x|zip^Vi-PQq#=d0r9;}<)&)QphL<<1L*>N#G diff --git a/scripts/altium365_part_request.py b/scripts/altium365_part_request.py index d757b3a..481552f 100644 --- a/scripts/altium365_part_request.py +++ b/scripts/altium365_part_request.py @@ -56,6 +56,7 @@ from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import TimeoutException def make_driver(debugger_address, chromedriver): @@ -122,7 +123,17 @@ def _attach_files(driver, files): def submit_request(driver, base, req, no_submit=False): driver.get(f"{base}/partrequestsmanagement/Tasks/Add") - _wait(driver, EC.presence_of_element_located((By.ID, "Manufacturer"))) + try: + _wait(driver, EC.presence_of_element_located((By.ID, "Manufacturer")), t=20) + except TimeoutException: + url = driver.current_url + if any(k in url.lower() for k in ("auth.altium.com", "signin", "login", "oauth")): + raise RuntimeError( + "NOT SIGNED IN — this Chrome (the one on the debug port) is on the Altium login " + "page, so the form never loaded. Open that same Chrome profile, sign into the " + "Workspace (keep me signed in), leave it open, and re-run.") + raise RuntimeError(f"The 'Add new request' form did not load (no #Manufacturer field). " + f"Current page URL: {url}") _set_text(driver, By.ID, "Manufacturer", req.get("manufacturer", "")) _set_text(driver, By.ID, "ManufacturerPartNumbers", req.get("mpn", "")) _set_text(driver, By.ID, "Description", req.get("description", "")) @@ -166,9 +177,10 @@ def main(): try: r = submit_request(driver, a.base.rstrip("/"), req, no_submit=no_submit) except Exception as e: - r = {"mpn": req.get("mpn"), "status": "error", "error": str(e)[:300]} + r = {"mpn": req.get("mpn"), "status": "error", "error": str(e).splitlines()[0][:400]} results.append(r) print(f"[{i+1}/{len(requests)}] {req.get('mpn')}: {r['status']}" + + (f" -> {r['error']}" if r.get("error") else "") + (f" MISSING {r['missing_files']}" if r.get("missing_files") else "")) if a.review_first and first and not a.no_submit: input("Review the first request in the browser, then press Enter to submit the rest...")