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/alt/python311/lib/python3.11/site-packages/typish
Viewing File: /opt/alt/python311/lib/python3.11/site-packages/typish/_functions.py
""" PRIVATE MODULE: do not import (from) it directly. This module contains the implementation of all functions of typish. """ import inspect import types import typing from collections import deque, defaultdict from collections.abc import Set from functools import lru_cache from inspect import getmro from typish._types import T, KT, VT, NoneType, Unknown, Empty def subclass_of(cls: type, *args: type) -> bool: """ Return whether ``cls`` is a subclass of all types in ``args`` while also considering generics. :param cls: the subject. :param args: the super types. :return: True if ``cls`` is a subclass of all types in ``args`` while also considering generics. """ if args and _is_literal(args[0]): return _check_literal(cls, subclass_of, *args) if len(args) > 1: result = subclass_of(cls, args[0]) and subclass_of(cls, *args[1:]) else: if args[0] == cls: return True result = _subclass_of(cls, args[0]) return result def instance_of(obj: object, *args: type) -> bool: """ Check whether ``obj`` is an instance of all types in ``args``, while also considering generics. :param obj: the object in subject. :param args: the type(s) of which ``obj`` is an instance or not. :return: ``True`` if ``obj`` is an instance of all types in ``args``. """ if args and _is_literal(args[0]): return _check_literal(obj, instance_of, *args) type_ = get_type(obj, use_union=True) return subclass_of(type_, *args) def get_origin(t: type) -> type: """ Return the origin of the given (generic) type. For example, for ``t=List[str]``, the result would be ``list``. :param t: the type of which the origin is to be found. :return: the origin of ``t`` or ``t`` if it is not generic. """ simple_name = _get_simple_name(t) result = _type_per_alias.get(simple_name, None) if not result: result = getattr(typing, simple_name, t) return result def get_args(t: type) -> typing.Tuple[type, ...]: """ Get the arguments from a collection type (e.g. ``typing.List[int]``) as a ``tuple``. :param t: the collection type. :return: a ``tuple`` containing types. """ args_ = getattr(t, '__args__', tuple()) or tuple() args = tuple([attr for attr in args_ if type(attr) != typing.TypeVar]) return args @lru_cache() def get_alias(cls: T) -> typing.Optional[T]: """ Return the alias from the ``typing`` module for ``cls``. For example, for ``cls=list``, the result would be ``typing.List``. If no alias exists for ``cls``, then ``None`` is returned. :param cls: the type for which the ``typing`` equivalent is to be found. :return: the alias from ``typing``. """ return _alias_per_type.get(cls.__name__, None) def get_type(inst: T, use_union: bool = False) -> typing.Type[T]: """ Return a type, complete with generics for the given ``inst``. :param inst: the instance for which a type is to be returned. :param use_union: if ``True``, the resulting type can contain a union. :return: the type of ``inst``. """ if inst is typing.Any: return typing.Any if str(inst).startswith('typing.Union'): return getattr(typing, '_GenericAlias', getattr(typing, 'GenericMeta', type)) result = type(inst) super_types = [ (dict, _get_type_dict), (tuple, _get_type_tuple), (str, lambda inst_, _: result), (typing.Iterable, _get_type_iterable), (types.FunctionType, _get_type_callable), (types.MethodType, _get_type_callable), (type, lambda inst_, _: typing.Type[inst]), ] try: for super_type, func in super_types: if isinstance(inst, super_type): result = func(inst, use_union) break except Exception: # If anything went wrong, return the regular type. # This is to support 3rd party libraries. return type(inst) return result def common_ancestor(*args: object) -> type: """ Get the closest common ancestor of the given objects. :param args: any objects. :return: the ``type`` of the closest common ancestor of the given ``args``. """ return _common_ancestor(args, False) def common_ancestor_of_types(*args: type) -> type: """ Get the closest common ancestor of the given classes. :param args: any classes. :return: the ``type`` of the closest common ancestor of the given ``args``. """ return _common_ancestor(args, True) def get_args_and_return_type(hint: typing.Type[typing.Callable]) \ -> typing.Tuple[typing.Optional[typing.Tuple[type]], typing.Optional[type]]: """ Get the argument types and the return type of a callable type hint (e.g. ``Callable[[int], str]``). Example: ``` arg_types, return_type = get_args_and_return_type(Callable[[int], str]) # args_types is (int, ) # return_type is str ``` Example for when ``hint`` has no generics: ``` arg_types, return_type = get_args_and_return_type(Callable) # args_types is None # return_type is None ``` :param hint: the callable type hint. :return: a tuple of the argument types (as a tuple) and the return type. """ if hint in (callable, typing.Callable): arg_types = None return_type = None elif hasattr(hint, '__result__'): arg_types = hint.__args__ return_type = hint.__result__ else: arg_types = hint.__args__[0:-1] return_type = hint.__args__[-1] return arg_types, return_type def get_type_hints_of_callable( func: typing.Callable) -> typing.Dict[str, type]: """ Return the type hints of the parameters of the given callable. :param func: the callable of which the type hints are to be returned. :return: a dict with parameter names and their types. """ # Python3.5: get_type_hints raises on classes without explicit constructor try: result = typing.get_type_hints(func) except AttributeError: result = {} return result def is_type_annotation(item: typing.Any) -> bool: """ Return whether item is a type annotation (a ``type`` or a type from ``typing``, such as ``List``). :param item: the item in question. :return: ``True`` is ``item`` is a type annotation. """ # Use _GenericAlias for Python 3.7+ and use GenericMeta for the rest. super_cls = getattr(typing, '_GenericAlias', getattr(typing, 'GenericMeta', None)) return (item is typing.Any or instance_of(item, type) or instance_of(item, super_cls)) def _subclass_of_generic( cls: type, info_generic_type: type, info_args: typing.Tuple[type, ...]) -> bool: # Check if cls is a subtype of info_generic_type, knowing that the latter # is a generic type. result = False cls_origin, cls_args = _split_generic(cls) if info_generic_type is tuple: # Special case. result = (subclass_of(cls_origin, tuple) and _subclass_of_tuple(cls_args, info_args)) elif cls_origin is tuple and info_generic_type is typing.Iterable: # Another special case. args = get_args(cls) if len(args) > 1 and args[1] is ...: args = [args[0]] ancestor = common_ancestor_of_types(*args) result = subclass_of(typing.Iterable[ancestor], typing.Iterable[args[0]]) elif info_generic_type is typing.Union: # Another special case. result = _subclass_of_union(cls, info_args) elif (subclass_of(cls_origin, info_generic_type) and cls_args and len(cls_args) == len(info_args)): for tup in zip(cls_args, info_args): if not subclass_of(*tup): result = False break else: result = True # Note that issubtype(list, List[...]) is always False. # Note that the number of arguments must be equal. return result def _subclass_of_tuple( cls_args: typing.Tuple[type, ...], info_args: typing.Tuple[type, ...]) -> bool: result = False if len(info_args) == 2 and info_args[1] is ...: type_ = get_origin(info_args[0]) if type_ is typing.Union: # A heterogeneous tuple: check each element if it subclasses the # union. result = all([subclass_of(elem, info_args[0]) for elem in cls_args]) else: result = subclass_of(common_ancestor_of_types(*cls_args), info_args[0]) elif len(cls_args) == len(info_args): for c1, c2 in zip(cls_args, info_args): if not subclass_of(c1, c2): break else: result = True return result def _split_generic(t: type) -> \ typing.Tuple[type, typing.Optional[typing.Tuple[type, ...]]]: # Split the given generic type into the type and its args. return get_origin(t), get_args(t) def _get_type_iterable(inst: typing.Iterable, use_union: bool): typing_type = get_alias(type(inst)) common_cls = Unknown if inst: if use_union: types = [get_type(elem) for elem in inst] common_cls = typing.Union[tuple(types)] else: common_cls = common_ancestor(*inst) if typing_type: if issubclass(common_cls, typing.Iterable) and typing_type is not str: # Get to the bottom of it; obtain types recursively. common_cls = get_type(common_cls(_flatten(inst))) result = typing_type[common_cls] return result def _get_type_tuple(inst: tuple, use_union: bool) -> typing.Dict[KT, VT]: args = [get_type(elem) for elem in inst] return typing.Tuple[tuple(args)] def _get_type_callable( inst: typing.Callable, use_union: bool) -> typing.Type[typing.Dict[KT, VT]]: if 'lambda' in str(inst): result = _get_type_lambda(inst, use_union) else: result = typing.Callable sig = inspect.signature(inst) args = [_map_empty(param.annotation) for param in sig.parameters.values()] return_type = NoneType if sig.return_annotation != Empty: return_type = sig.return_annotation if args or return_type != NoneType: if inspect.iscoroutinefunction(inst): return_type = typing.Awaitable[return_type] result = typing.Callable[args, return_type] return result def _map_empty(annotation: type) -> type: result = annotation if annotation == Empty: result = typing.Any return result def _get_type_lambda( inst: typing.Callable, use_union: bool) -> typing.Type[typing.Dict[KT, VT]]: args = [Unknown for _ in inspect.signature(inst).parameters] return_type = Unknown return typing.Callable[args, return_type] def _get_type_dict(inst: typing.Dict[KT, VT], use_union: bool) -> typing.Type[typing.Dict[KT, VT]]: t_list_k = _get_type_iterable(list(inst.keys()), use_union) t_list_v = _get_type_iterable(list(inst.values()), use_union) _, t_k_tuple = _split_generic(t_list_k) _, t_v_tuple = _split_generic(t_list_v) return typing.Dict[t_k_tuple[0], t_v_tuple[0]] def _flatten(l: typing.Iterable[typing.Iterable[typing.Any]]) -> typing.List[typing.Any]: result = [] for x in l: result += [*x] return result def _common_ancestor(args: typing.Sequence[object], types: bool) -> type: if len(args) < 1: raise TypeError('common_ancestor() requires at least 1 argument') tmap = (lambda x: x) if types else get_type mros = [_get_mro(tmap(elem)) for elem in args] for cls in mros[0]: for mro in mros: if cls not in mro: break else: # cls is in every mro; a common ancestor is found! return cls def _subclass_of(cls: type, clsinfo: type) -> bool: # Check whether cls is a subtype of clsinfo. clsinfo_origin, info_args = _split_generic(clsinfo) cls_origin = get_origin(cls) if cls is Unknown or clsinfo in (typing.Any, object): result = True elif cls_origin is typing.Union: # cls is a Union; all options of that Union must subclass clsinfo. _, cls_args = _split_generic(cls) result = all([subclass_of(elem, clsinfo) for elem in cls_args]) elif info_args: result = _subclass_of_generic(cls, clsinfo_origin, info_args) else: try: result = issubclass(cls_origin, clsinfo_origin) except TypeError: result = False return result def _subclass_of_union( cls: type, info_args: typing.Tuple[type, ...]) -> bool: # Handle subclass_of(*, union) result = True for cls_ in info_args: if subclass_of(cls, cls_): break else: result = False return result @lru_cache() def _get_simple_name(cls: type) -> str: if cls is None: cls = type(cls) cls_name = getattr(cls, '__name__', None) if not cls_name: cls_name = getattr(cls, '_name', None) if not cls_name: cls_name = repr(cls) cls_name = cls_name.split('[')[0] # Remove generic types. cls_name = cls_name.split('.')[-1] # Remove any . caused by repr. cls_name = cls_name.split(r"'>")[0] # Remove any '>. return cls_name def _get_mro(cls: type) -> typing.Tuple[type, ...]: # Wrapper around ``getmro`` to allow types from ``Typing``. if cls is ...: return Ellipsis, object elif cls is typing.Union: # For Python <3.7, we cannot use mro. super_cls = getattr(typing, '_GenericAlias', getattr(typing, 'GenericMeta', None)) return (typing.Union, super_cls, object) origin, args = _split_generic(cls) if origin != cls: return _get_mro(origin) return getmro(cls) def _is_literal(arg: typing.Any) -> bool: # Return True if arg is a Literal. origin = get_origin(arg) return getattr(origin, '_name', None) == 'Literal' def _check_literal(obj: object, func: typing.Callable, *args: type) -> bool: # Instance or subclass check for Literal. literal = args[0] leftovers = args[1:] literal_args = getattr(literal, '__args__', None) if literal_args: literal_arg = literal_args[0] return obj == literal_arg and (not leftovers or func(obj, *leftovers)) return False _alias_per_type = { 'list': typing.List, 'tuple': typing.Tuple, 'dict': typing.Dict, 'set': typing.Set, 'frozenset': typing.FrozenSet, 'deque': typing.Deque, 'defaultdict': typing.DefaultDict, 'type': typing.Type, 'Set': typing.AbstractSet, } _type_per_alias = { 'List': list, 'Tuple': tuple, 'Dict': dict, 'Set': set, 'FrozenSet': frozenset, 'Deque': deque, 'DefaultDict': defaultdict, 'Type': type, 'AbstractSet': Set, }