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: /usr/lib/imh-dnskeyapi/venv/lib/python3.13/site-packages/werkzeug/datastructures
Viewing File: /usr/lib/imh-dnskeyapi/venv/lib/python3.13/site-packages/werkzeug/datastructures/headers.py
from __future__ import annotations import collections.abc as cabc import re import typing as t from .._internal import _missing from ..exceptions import BadRequestKeyError from .mixins import ImmutableHeadersMixin from .structures import iter_multi_items from .structures import MultiDict if t.TYPE_CHECKING: import typing_extensions as te from _typeshed.wsgi import WSGIEnvironment T = t.TypeVar("T") class Headers: """An object that stores some headers. It has a dict-like interface, but is ordered, can store the same key multiple times, and iterating yields ``(key, value)`` pairs instead of only keys. This data structure is useful if you want a nicer way to handle WSGI headers which are stored as tuples in a list. From Werkzeug 0.3 onwards, the :exc:`KeyError` raised by this class is also a subclass of the :class:`~exceptions.BadRequest` HTTP exception and will render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP exceptions. Headers is mostly compatible with the Python :class:`wsgiref.headers.Headers` class, with the exception of `__getitem__`. :mod:`wsgiref` will return `None` for ``headers['missing']``, whereas :class:`Headers` will raise a :class:`KeyError`. To create a new ``Headers`` object, pass it a list, dict, or other ``Headers`` object with default values. These values are validated the same way values added later are. :param defaults: The list of default values for the :class:`Headers`. .. versionchanged:: 3.1 Implement ``|`` and ``|=`` operators. .. versionchanged:: 2.1.0 Default values are validated the same as values added later. .. versionchanged:: 0.9 This data structure now stores unicode values similar to how the multi dicts do it. The main difference is that bytes can be set as well which will automatically be latin1 decoded. .. versionchanged:: 0.9 The :meth:`linked` function was removed without replacement as it was an API that does not support the changes to the encoding model. """ def __init__( self, defaults: ( Headers | MultiDict[str, t.Any] | cabc.Mapping[str, t.Any | list[t.Any] | tuple[t.Any, ...] | set[t.Any]] | cabc.Iterable[tuple[str, t.Any]] | None ) = None, ) -> None: self._list: list[tuple[str, str]] = [] if defaults is not None: self.extend(defaults) @t.overload def __getitem__(self, key: str) -> str: ... @t.overload def __getitem__(self, key: int) -> tuple[str, str]: ... @t.overload def __getitem__(self, key: slice) -> te.Self: ... def __getitem__(self, key: str | int | slice) -> str | tuple[str, str] | te.Self: if isinstance(key, str): return self._get_key(key) if isinstance(key, int): return self._list[key] return self.__class__(self._list[key]) def _get_key(self, key: str) -> str: ikey = key.lower() for k, v in self._list: if k.lower() == ikey: return v raise BadRequestKeyError(key) def __eq__(self, other: object) -> bool: if other.__class__ is not self.__class__: return NotImplemented def lowered(item: tuple[str, ...]) -> tuple[str, ...]: return item[0].lower(), *item[1:] return set(map(lowered, other._list)) == set(map(lowered, self._list)) # type: ignore[attr-defined] __hash__ = None # type: ignore[assignment] @t.overload def get(self, key: str) -> str | None: ... @t.overload def get(self, key: str, default: str) -> str: ... @t.overload def get(self, key: str, default: T) -> str | T: ... @t.overload def get(self, key: str, type: cabc.Callable[[str], T]) -> T | None: ... @t.overload def get(self, key: str, default: T, type: cabc.Callable[[str], T]) -> T: ... def get( # type: ignore[misc] self, key: str, default: str | T | None = None, type: cabc.Callable[[str], T] | None = None, ) -> str | T | None: """Return the default value if the requested data doesn't exist. If `type` is provided and is a callable it should convert the value, return it or raise a :exc:`ValueError` if that is not possible. In this case the function will return the default as if the value was not found: >>> d = Headers([('Content-Length', '42')]) >>> d.get('Content-Length', type=int) 42 :param key: The key to be looked up. :param default: The default value to be returned if the key can't be looked up. If not further specified `None` is returned. :param type: A callable that is used to cast the value in the :class:`Headers`. If a :exc:`ValueError` is raised by this callable the default value is returned. .. versionchanged:: 3.0 The ``as_bytes`` parameter was removed. .. versionchanged:: 0.9 The ``as_bytes`` parameter was added. """ try: rv = self._get_key(key) except KeyError: return default if type is None: return rv try: return type(rv) except ValueError: return default @t.overload def getlist(self, key: str) -> list[str]: ... @t.overload def getlist(self, key: str, type: cabc.Callable[[str], T]) -> list[T]: ... def getlist( self, key: str, type: cabc.Callable[[str], T] | None = None ) -> list[str] | list[T]: """Return the list of items for a given key. If that key is not in the :class:`Headers`, the return value will be an empty list. Just like :meth:`get`, :meth:`getlist` accepts a `type` parameter. All items will be converted with the callable defined there. :param key: The key to be looked up. :param type: A callable that is used to cast the value in the :class:`Headers`. If a :exc:`ValueError` is raised by this callable the value will be removed from the list. :return: a :class:`list` of all the values for the key. .. versionchanged:: 3.0 The ``as_bytes`` parameter was removed. .. versionchanged:: 0.9 The ``as_bytes`` parameter was added. """ ikey = key.lower() if type is not None: result = [] for k, v in self: if k.lower() == ikey: try: result.append(type(v)) except ValueError: continue return result return [v for k, v in self if k.lower() == ikey] def get_all(self, name: str) -> list[str]: """Return a list of all the values for the named field. This method is compatible with the :mod:`wsgiref` :meth:`~wsgiref.headers.Headers.get_all` method. """ return self.getlist(name) def items(self, lower: bool = False) -> t.Iterable[tuple[str, str]]: for key, value in self: if lower: key = key.lower() yield key, value def keys(self, lower: bool = False) -> t.Iterable[str]: for key, _ in self.items(lower): yield key def values(self) -> t.Iterable[str]: for _, value in self.items(): yield value def extend( self, arg: ( Headers | MultiDict[str, t.Any] | cabc.Mapping[str, t.Any | list[t.Any] | tuple[t.Any, ...] | set[t.Any]] | cabc.Iterable[tuple[str, t.Any]] | None ) = None, /, **kwargs: str, ) -> None: """Extend headers in this object with items from another object containing header items as well as keyword arguments. To replace existing keys instead of extending, use :meth:`update` instead. If provided, the first argument can be another :class:`Headers` object, a :class:`MultiDict`, :class:`dict`, or iterable of pairs. .. versionchanged:: 1.0 Support :class:`MultiDict`. Allow passing ``kwargs``. """ if arg is not None: for key, value in iter_multi_items(arg): self.add(key, value) for key, value in iter_multi_items(kwargs): self.add(key, value) def __delitem__(self, key: str | int | slice) -> None: if isinstance(key, str): self._del_key(key) return del self._list[key] def _del_key(self, key: str) -> None: key = key.lower() new = [] for k, v in self._list: if k.lower() != key: new.append((k, v)) self._list[:] = new def remove(self, key: str) -> None: """Remove a key. :param key: The key to be removed. """ return self._del_key(key) @t.overload def pop(self) -> tuple[str, str]: ... @t.overload def pop(self, key: str) -> str: ... @t.overload def pop(self, key: int | None = ...) -> tuple[str, str]: ... @t.overload def pop(self, key: str, default: str) -> str: ... @t.overload def pop(self, key: str, default: T) -> str | T: ... def pop( self, key: str | int | None = None, default: str | T = _missing, # type: ignore[assignment] ) -> str | tuple[str, str] | T: """Removes and returns a key or index. :param key: The key to be popped. If this is an integer the item at that position is removed, if it's a string the value for that key is. If the key is omitted or `None` the last item is removed. :return: an item. """ if key is None: return self._list.pop() if isinstance(key, int): return self._list.pop(key) try: rv = self._get_key(key) except KeyError: if default is not _missing: return default raise self.remove(key) return rv def popitem(self) -> tuple[str, str]: """Removes a key or index and returns a (key, value) item.""" return self._list.pop() def __contains__(self, key: str) -> bool: """Check if a key is present.""" try: self._get_key(key) except KeyError: return False return True def __iter__(self) -> t.Iterator[tuple[str, str]]: """Yield ``(key, value)`` tuples.""" return iter(self._list) def __len__(self) -> int: return len(self._list) def add(self, key: str, value: t.Any, /, **kwargs: t.Any) -> None: """Add a new header tuple to the list. Keyword arguments can specify additional parameters for the header value, with underscores converted to dashes:: >>> d = Headers() >>> d.add('Content-Type', 'text/plain') >>> d.add('Content-Disposition', 'attachment', filename='foo.png') The keyword argument dumping uses :func:`dump_options_header` behind the scenes. .. versionchanged:: 0.4.1 keyword arguments were added for :mod:`wsgiref` compatibility. """ if kwargs: value = _options_header_vkw(value, kwargs) value_str = _str_header_value(value) self._list.append((key, value_str)) def add_header(self, key: str, value: t.Any, /, **kwargs: t.Any) -> None: """Add a new header tuple to the list. An alias for :meth:`add` for compatibility with the :mod:`wsgiref` :meth:`~wsgiref.headers.Headers.add_header` method. """ self.add(key, value, **kwargs) def clear(self) -> None: """Clears all headers.""" self._list.clear() def set(self, key: str, value: t.Any, /, **kwargs: t.Any) -> None: """Remove all header tuples for `key` and add a new one. The newly added key either appears at the end of the list if there was no entry or replaces the first one. Keyword arguments can specify additional parameters for the header value, with underscores converted to dashes. See :meth:`add` for more information. .. versionchanged:: 0.6.1 :meth:`set` now accepts the same arguments as :meth:`add`. :param key: The key to be inserted. :param value: The value to be inserted. """ if kwargs: value = _options_header_vkw(value, kwargs) value_str = _str_header_value(value) if not self._list: self._list.append((key, value_str)) return iter_list = iter(self._list) ikey = key.lower() for idx, (old_key, _) in enumerate(iter_list): if old_key.lower() == ikey: # replace first occurrence self._list[idx] = (key, value_str) break else: # no existing occurrences self._list.append((key, value_str)) return # remove remaining occurrences self._list[idx + 1 :] = [t for t in iter_list if t[0].lower() != ikey] def setlist(self, key: str, values: cabc.Iterable[t.Any]) -> None: """Remove any existing values for a header and add new ones. :param key: The header key to set. :param values: An iterable of values to set for the key. .. versionadded:: 1.0 """ if values: values_iter = iter(values) self.set(key, next(values_iter)) for value in values_iter: self.add(key, value) else: self.remove(key) def setdefault(self, key: str, default: t.Any) -> str: """Return the first value for the key if it is in the headers, otherwise set the header to the value given by ``default`` and return that. :param key: The header key to get. :param default: The value to set for the key if it is not in the headers. """ try: return self._get_key(key) except KeyError: pass self.set(key, default) return self._get_key(key) def setlistdefault(self, key: str, default: cabc.Iterable[t.Any]) -> list[str]: """Return the list of values for the key if it is in the headers, otherwise set the header to the list of values given by ``default`` and return that. Unlike :meth:`MultiDict.setlistdefault`, modifying the returned list will not affect the headers. :param key: The header key to get. :param default: An iterable of values to set for the key if it is not in the headers. .. versionadded:: 1.0 """ if key not in self: self.setlist(key, default) return self.getlist(key) @t.overload def __setitem__(self, key: str, value: t.Any) -> None: ... @t.overload def __setitem__(self, key: int, value: tuple[str, t.Any]) -> None: ... @t.overload def __setitem__( self, key: slice, value: cabc.Iterable[tuple[str, t.Any]] ) -> None: ... def __setitem__( self, key: str | int | slice, value: t.Any | tuple[str, t.Any] | cabc.Iterable[tuple[str, t.Any]], ) -> None: """Like :meth:`set` but also supports index/slice based setting.""" if isinstance(key, str): self.set(key, value) elif isinstance(key, int): self._list[key] = value[0], _str_header_value(value[1]) # type: ignore[index] else: self._list[key] = [(k, _str_header_value(v)) for k, v in value] # type: ignore[misc] def update( self, arg: ( Headers | MultiDict[str, t.Any] | cabc.Mapping[ str, t.Any | list[t.Any] | tuple[t.Any, ...] | cabc.Set[t.Any] ] | cabc.Iterable[tuple[str, t.Any]] | None ) = None, /, **kwargs: t.Any | list[t.Any] | tuple[t.Any, ...] | cabc.Set[t.Any], ) -> None: """Replace headers in this object with items from another headers object and keyword arguments. To extend existing keys instead of replacing, use :meth:`extend` instead. If provided, the first argument can be another :class:`Headers` object, a :class:`MultiDict`, :class:`dict`, or iterable of pairs. .. versionadded:: 1.0 """ if arg is not None: if isinstance(arg, (Headers, MultiDict)): for key in arg.keys(): self.setlist(key, arg.getlist(key)) elif isinstance(arg, cabc.Mapping): for key, value in arg.items(): if isinstance(value, (list, tuple, set)): self.setlist(key, value) else: self.set(key, value) else: for key, value in arg: self.set(key, value) for key, value in kwargs.items(): if isinstance(value, (list, tuple, set)): self.setlist(key, value) else: self.set(key, value) def __or__( self, other: cabc.Mapping[ str, t.Any | list[t.Any] | tuple[t.Any, ...] | cabc.Set[t.Any] ], ) -> te.Self: if not isinstance(other, cabc.Mapping): return NotImplemented rv = self.copy() rv.update(other) return rv def __ior__( self, other: ( cabc.Mapping[str, t.Any | list[t.Any] | tuple[t.Any, ...] | cabc.Set[t.Any]] | cabc.Iterable[tuple[str, t.Any]] ), ) -> te.Self: if not isinstance(other, (cabc.Mapping, cabc.Iterable)): return NotImplemented self.update(other) return self def to_wsgi_list(self) -> list[tuple[str, str]]: """Convert the headers into a list suitable for WSGI. :return: list """ return list(self) def copy(self) -> te.Self: return self.__class__(self._list) def __copy__(self) -> te.Self: return self.copy() def __str__(self) -> str: """Returns formatted headers suitable for HTTP transmission.""" strs = [] for key, value in self.to_wsgi_list(): strs.append(f"{key}: {value}") strs.append("\r\n") return "\r\n".join(strs) def __repr__(self) -> str: return f"{type(self).__name__}({list(self)!r})" def _options_header_vkw(value: str, kw: dict[str, t.Any]) -> str: return http.dump_options_header( value, {k.replace("_", "-"): v for k, v in kw.items()} ) _newline_re = re.compile(r"[\r\n]") def _str_header_value(value: t.Any) -> str: if not isinstance(value, str): value = str(value) if _newline_re.search(value) is not None: raise ValueError("Header values must not contain newline characters.") return value # type: ignore[no-any-return] class EnvironHeaders(ImmutableHeadersMixin, Headers): # type: ignore[misc] """Read only version of the headers from a WSGI environment. This provides the same interface as `Headers` and is constructed from a WSGI environment. From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP exceptions. """ def __init__(self, environ: WSGIEnvironment) -> None: super().__init__() self.environ = environ def __eq__(self, other: object) -> bool: if not isinstance(other, EnvironHeaders): return NotImplemented return self.environ is other.environ __hash__ = None # type: ignore[assignment] def __getitem__(self, key: str) -> str: # type: ignore[override] return self._get_key(key) def _get_key(self, key: str) -> str: if not isinstance(key, str): raise BadRequestKeyError(key) key = key.upper().replace("-", "_") if key in {"CONTENT_TYPE", "CONTENT_LENGTH"}: return self.environ[key] # type: ignore[no-any-return] return self.environ[f"HTTP_{key}"] # type: ignore[no-any-return] def __len__(self) -> int: return sum(1 for _ in self) def __iter__(self) -> cabc.Iterator[tuple[str, str]]: for key, value in self.environ.items(): if key.startswith("HTTP_") and key not in { "HTTP_CONTENT_TYPE", "HTTP_CONTENT_LENGTH", }: yield key[5:].replace("_", "-").title(), value elif key in {"CONTENT_TYPE", "CONTENT_LENGTH"} and value: yield key.replace("_", "-").title(), value def copy(self) -> t.NoReturn: raise TypeError(f"cannot create {type(self).__name__!r} copies") def __or__(self, other: t.Any) -> t.NoReturn: raise TypeError(f"cannot create {type(self).__name__!r} copies") # circular dependencies from .. import http