PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/imh-python/lib/python3.9/site-packages/werkzeug/debug
Viewing File: /opt/imh-python/lib/python3.9/site-packages/werkzeug/debug/tbtools.py
import codecs import inspect import os import re import sys import sysconfig import traceback import typing as t from html import escape from tokenize import TokenError from types import CodeType from types import TracebackType from .._internal import _to_str from ..filesystem import get_filesystem_encoding from ..utils import cached_property from .console import Console _coding_re = re.compile(rb"coding[:=]\s*([-\w.]+)") _line_re = re.compile(rb"^(.*?)$", re.MULTILINE) _funcdef_re = re.compile(r"^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)") HEADER = """\ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>%(title)s // Werkzeug Debugger</title> <link rel="stylesheet" href="?__debugger__=yes&amp;cmd=resource&amp;f=style.css" type="text/css"> <!-- We need to make sure this has a favicon so that the debugger does not accidentally trigger a request to /favicon.ico which might change the application's state. --> <link rel="shortcut icon" href="?__debugger__=yes&amp;cmd=resource&amp;f=console.png"> <script src="?__debugger__=yes&amp;cmd=resource&amp;f=debugger.js"></script> <script type="text/javascript"> var TRACEBACK = %(traceback_id)d, CONSOLE_MODE = %(console)s, EVALEX = %(evalex)s, EVALEX_TRUSTED = %(evalex_trusted)s, SECRET = "%(secret)s"; </script> </head> <body style="background-color: #fff"> <div class="debugger"> """ FOOTER = """\ <div class="footer"> Brought to you by <strong class="arthur">DON'T PANIC</strong>, your friendly Werkzeug powered traceback interpreter. </div> </div> <div class="pin-prompt"> <div class="inner"> <h3>Console Locked</h3> <p> The console is locked and needs to be unlocked by entering the PIN. You can find the PIN printed out on the standard output of your shell that runs the server. <form> <p>PIN: <input type=text name=pin size=14> <input type=submit name=btn value="Confirm Pin"> </form> </div> </div> </body> </html> """ PAGE_HTML = ( HEADER + """\ <h1>%(exception_type)s</h1> <div class="detail"> <p class="errormsg">%(exception)s</p> </div> <h2 class="traceback">Traceback <em>(most recent call last)</em></h2> %(summary)s <div class="plain"> <p> This is the Copy/Paste friendly version of the traceback. </p> <textarea cols="50" rows="10" name="code" readonly>%(plaintext)s</textarea> </div> <div class="explanation"> The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error. <span class="nojavascript"> If you enable JavaScript you can also use additional features such as code execution (if the evalex feature is enabled), automatic pasting of the exceptions and much more.</span> </div> """ + FOOTER + """ <!-- %(plaintext_cs)s --> """ ) CONSOLE_HTML = ( HEADER + """\ <h1>Interactive Console</h1> <div class="explanation"> In this console you can execute Python expressions in the context of the application. The initial namespace was created by the debugger automatically. </div> <div class="console"><div class="inner">The Console requires JavaScript.</div></div> """ + FOOTER ) SUMMARY_HTML = """\ <div class="%(classes)s"> %(title)s <ul>%(frames)s</ul> %(description)s </div> """ FRAME_HTML = """\ <div class="frame" id="frame-%(id)d"> <h4>File <cite class="filename">"%(filename)s"</cite>, line <em class="line">%(lineno)s</em>, in <code class="function">%(function_name)s</code></h4> <div class="source %(library)s">%(lines)s</div> </div> """ SOURCE_LINE_HTML = """\ <tr class="%(classes)s"> <td class=lineno>%(lineno)s</td> <td>%(code)s</td> </tr> """ def render_console_html(secret: str, evalex_trusted: bool = True) -> str: return CONSOLE_HTML % { "evalex": "true", "evalex_trusted": "true" if evalex_trusted else "false", "console": "true", "title": "Console", "secret": secret, "traceback_id": -1, } def get_current_traceback( ignore_system_exceptions: bool = False, show_hidden_frames: bool = False, skip: int = 0, ) -> "Traceback": """Get the current exception info as `Traceback` object. Per default calling this method will reraise system exceptions such as generator exit, system exit or others. This behavior can be disabled by passing `False` to the function as first parameter. """ info = t.cast( t.Tuple[t.Type[BaseException], BaseException, TracebackType], sys.exc_info() ) exc_type, exc_value, tb = info if ignore_system_exceptions and exc_type in { SystemExit, KeyboardInterrupt, GeneratorExit, }: raise for _ in range(skip): if tb.tb_next is None: break tb = tb.tb_next tb = Traceback(exc_type, exc_value, tb) if not show_hidden_frames: tb.filter_hidden_frames() return tb class Line: """Helper for the source renderer.""" __slots__ = ("lineno", "code", "in_frame", "current") def __init__(self, lineno: int, code: str) -> None: self.lineno = lineno self.code = code self.in_frame = False self.current = False @property def classes(self) -> t.List[str]: rv = ["line"] if self.in_frame: rv.append("in-frame") if self.current: rv.append("current") return rv def render(self) -> str: return SOURCE_LINE_HTML % { "classes": " ".join(self.classes), "lineno": self.lineno, "code": escape(self.code), } class Traceback: """Wraps a traceback.""" def __init__( self, exc_type: t.Type[BaseException], exc_value: BaseException, tb: TracebackType, ) -> None: self.exc_type = exc_type self.exc_value = exc_value self.tb = tb exception_type = exc_type.__name__ if exc_type.__module__ not in {"builtins", "__builtin__", "exceptions"}: exception_type = f"{exc_type.__module__}.{exception_type}" self.exception_type = exception_type self.groups = [] memo = set() while True: self.groups.append(Group(exc_type, exc_value, tb)) memo.add(id(exc_value)) exc_value = exc_value.__cause__ or exc_value.__context__ # type: ignore if exc_value is None or id(exc_value) in memo: break exc_type = type(exc_value) tb = exc_value.__traceback__ # type: ignore self.groups.reverse() self.frames = [frame for group in self.groups for frame in group.frames] def filter_hidden_frames(self) -> None: """Remove the frames according to the paste spec.""" for group in self.groups: group.filter_hidden_frames() self.frames[:] = [frame for group in self.groups for frame in group.frames] @property def is_syntax_error(self) -> bool: """Is it a syntax error?""" return isinstance(self.exc_value, SyntaxError) @property def exception(self) -> str: """String representation of the final exception.""" return self.groups[-1].exception def log(self, logfile: t.Optional[t.IO[str]] = None) -> None: """Log the ASCII traceback into a file object.""" if logfile is None: logfile = sys.stderr tb = f"{self.plaintext.rstrip()}\n" logfile.write(tb) def render_summary(self, include_title: bool = True) -> str: """Render the traceback for the interactive console.""" title = "" classes = ["traceback"] if not self.frames: classes.append("noframe-traceback") frames = [] else: library_frames = sum(frame.is_library for frame in self.frames) mark_lib = 0 < library_frames < len(self.frames) frames = [group.render(mark_lib=mark_lib) for group in self.groups] if include_title: if self.is_syntax_error: title = "Syntax Error" else: title = "Traceback <em>(most recent call last)</em>:" if self.is_syntax_error: description = f"<pre class=syntaxerror>{escape(self.exception)}</pre>" else: description = f"<blockquote>{escape(self.exception)}</blockquote>" return SUMMARY_HTML % { "classes": " ".join(classes), "title": f"<h3>{title if title else ''}</h3>", "frames": "\n".join(frames), "description": description, } def render_full( self, evalex: bool = False, secret: t.Optional[str] = None, evalex_trusted: bool = True, ) -> str: """Render the Full HTML page with the traceback info.""" exc = escape(self.exception) return PAGE_HTML % { "evalex": "true" if evalex else "false", "evalex_trusted": "true" if evalex_trusted else "false", "console": "false", "title": exc, "exception": exc, "exception_type": escape(self.exception_type), "summary": self.render_summary(include_title=False), "plaintext": escape(self.plaintext), "plaintext_cs": re.sub("-{2,}", "-", self.plaintext), "traceback_id": self.id, "secret": secret, } @cached_property def plaintext(self) -> str: return "\n".join([group.render_text() for group in self.groups]) @property def id(self) -> int: return id(self) class Group: """A group of frames for an exception in a traceback. If the exception has a ``__cause__`` or ``__context__``, there are multiple exception groups. """ def __init__( self, exc_type: t.Type[BaseException], exc_value: BaseException, tb: TracebackType, ) -> None: self.exc_type = exc_type self.exc_value = exc_value self.info = None if exc_value.__cause__ is not None: self.info = ( "The above exception was the direct cause of the following exception" ) elif exc_value.__context__ is not None: self.info = ( "During handling of the above exception, another exception occurred" ) self.frames = [] while tb is not None: self.frames.append(Frame(exc_type, exc_value, tb)) tb = tb.tb_next # type: ignore def filter_hidden_frames(self) -> None: # An exception may not have a traceback to filter frames, such # as one re-raised from ProcessPoolExecutor. if not self.frames: return new_frames: t.List[Frame] = [] hidden = False for frame in self.frames: hide = frame.hide if hide in ("before", "before_and_this"): new_frames = [] hidden = False if hide == "before_and_this": continue elif hide in ("reset", "reset_and_this"): hidden = False if hide == "reset_and_this": continue elif hide in ("after", "after_and_this"): hidden = True if hide == "after_and_this": continue elif hide or hidden: continue new_frames.append(frame) # if we only have one frame and that frame is from the codeop # module, remove it. if len(new_frames) == 1 and self.frames[0].module == "codeop": del self.frames[:] # if the last frame is missing something went terrible wrong :( elif self.frames[-1] in new_frames: self.frames[:] = new_frames @property def exception(self) -> str: """String representation of the exception.""" buf = traceback.format_exception_only(self.exc_type, self.exc_value) rv = "".join(buf).strip() return _to_str(rv, "utf-8", "replace") def render(self, mark_lib: bool = True) -> str: out = [] if self.info is not None: out.append(f'<li><div class="exc-divider">{self.info}:</div>') for frame in self.frames: title = f' title="{escape(frame.info)}"' if frame.info else "" out.append(f"<li{title}>{frame.render(mark_lib=mark_lib)}") return "\n".join(out) def render_text(self) -> str: out = [] if self.info is not None: out.append(f"\n{self.info}:\n") out.append("Traceback (most recent call last):") for frame in self.frames: out.append(frame.render_text()) out.append(self.exception) return "\n".join(out) class Frame: """A single frame in a traceback.""" def __init__( self, exc_type: t.Type[BaseException], exc_value: BaseException, tb: TracebackType, ) -> None: self.lineno = tb.tb_lineno self.function_name = tb.tb_frame.f_code.co_name self.locals = tb.tb_frame.f_locals self.globals = tb.tb_frame.f_globals fn = inspect.getsourcefile(tb) or inspect.getfile(tb) if fn[-4:] in (".pyo", ".pyc"): fn = fn[:-1] # if it's a file on the file system resolve the real filename. if os.path.isfile(fn): fn = os.path.realpath(fn) self.filename = _to_str(fn, get_filesystem_encoding()) self.module = self.globals.get("__name__", self.locals.get("__name__")) self.loader = self.globals.get("__loader__", self.locals.get("__loader__")) self.code = tb.tb_frame.f_code # support for paste's traceback extensions self.hide = self.locals.get("__traceback_hide__", False) info = self.locals.get("__traceback_info__") if info is not None: info = _to_str(info, "utf-8", "replace") self.info = info def render(self, mark_lib: bool = True) -> str: """Render a single frame in a traceback.""" return FRAME_HTML % { "id": self.id, "filename": escape(self.filename), "lineno": self.lineno, "function_name": escape(self.function_name), "lines": self.render_line_context(), "library": "library" if mark_lib and self.is_library else "", } @cached_property def is_library(self) -> bool: return any( self.filename.startswith(os.path.realpath(path)) for path in sysconfig.get_paths().values() ) def render_text(self) -> str: return ( f' File "{self.filename}", line {self.lineno}, in {self.function_name}\n' f" {self.current_line.strip()}" ) def render_line_context(self) -> str: before, current, after = self.get_context_lines() rv = [] def render_line(line: str, cls: str) -> None: line = line.expandtabs().rstrip() stripped_line = line.strip() prefix = len(line) - len(stripped_line) rv.append( f'<pre class="line {cls}"><span class="ws">{" " * prefix}</span>' f"{escape(stripped_line) if stripped_line else ' '}</pre>" ) for line in before: render_line(line, "before") render_line(current, "current") for line in after: render_line(line, "after") return "\n".join(rv) def get_annotated_lines(self) -> t.List[Line]: """Helper function that returns lines with extra information.""" lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)] # find function definition and mark lines if hasattr(self.code, "co_firstlineno"): lineno = self.code.co_firstlineno - 1 while lineno > 0: if _funcdef_re.match(lines[lineno].code): break lineno -= 1 try: offset = len(inspect.getblock([f"{x.code}\n" for x in lines[lineno:]])) except TokenError: offset = 0 for line in lines[lineno : lineno + offset]: line.in_frame = True # mark current line try: lines[self.lineno - 1].current = True except IndexError: pass return lines def eval(self, code: t.Union[str, CodeType], mode: str = "single") -> t.Any: """Evaluate code in the context of the frame.""" if isinstance(code, str): code = compile(code, "<interactive>", mode) return eval(code, self.globals, self.locals) @cached_property def sourcelines(self) -> t.List[str]: """The sourcecode of the file as list of strings.""" # get sourcecode from loader or file source = None if self.loader is not None: try: if hasattr(self.loader, "get_source"): source = self.loader.get_source(self.module) elif hasattr(self.loader, "get_source_by_code"): source = self.loader.get_source_by_code(self.code) except Exception: # we munch the exception so that we don't cause troubles # if the loader is broken. pass if source is None: try: with open(self.filename, mode="rb") as f: source = f.read() except OSError: return [] # already str? return right away if isinstance(source, str): return source.splitlines() charset = "utf-8" if source.startswith(codecs.BOM_UTF8): source = source[3:] else: for idx, match in enumerate(_line_re.finditer(source)): coding_match = _coding_re.search(match.group()) if coding_match is not None: charset = coding_match.group(1).decode("utf-8") break if idx > 1: break # on broken cookies we fall back to utf-8 too charset = _to_str(charset) try: codecs.lookup(charset) except LookupError: charset = "utf-8" return source.decode(charset, "replace").splitlines() def get_context_lines( self, context: int = 5 ) -> t.Tuple[t.List[str], str, t.List[str]]: before = self.sourcelines[self.lineno - context - 1 : self.lineno - 1] past = self.sourcelines[self.lineno : self.lineno + context] return (before, self.current_line, past) @property def current_line(self) -> str: try: return self.sourcelines[self.lineno - 1] except IndexError: return "" @cached_property def console(self) -> Console: return Console(self.globals, self.locals) @property def id(self) -> int: return id(self)