TTc@sLddlZddlmZddlmZddlmZmZmZmZddlm Z m Z m Z m Z m Z mZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z!ddlm"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(ddl)m*Z*d e+fd YZ,dS( iNi(tast(tmessage(tTAG_DEPRECATEDt TAG_SINCEt TAG_STABILITYt TAG_RETURNS(tANN_ALLOW_NONEt ANN_ARRAYtANN_ATTRIBUTESt ANN_CLOSUREtANN_CONSTRUCTORt ANN_DESTROYtANN_ELEMENT_TYPEt ANN_FOREIGNtANN_GET_VALUE_FUNCtANN_INt ANN_INOUTt ANN_METHODtANN_OUTt ANN_REF_FUNCt ANN_RENAME_TOt ANN_SCOPEtANN_SET_VALUE_FUNCtANN_SKIPt ANN_TRANSFERtANN_TYPEtANN_UNREF_FUNCt ANN_VALUEt ANN_VFUNCt ANN_NULLABLEt ANN_OPTIONAL(tOPT_ARRAY_FIXED_SIZEtOPT_ARRAY_LENGTHtOPT_ARRAY_ZERO_TERMINATEDtOPT_OUT_CALLEE_ALLOCATEStOPT_OUT_CALLER_ALLOCATEStOPT_TRANSFER_FLOATINGtOPT_TRANSFER_NONE(tto_underscores_noprefixtMainTransformercBseZdZdZdZdZdZdZdZdZ dZ d Z d Z d Z d Zd8d8d8d Zd8d8d8dZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"d Z#d!Z$d"Z%d#Z&d$Z'd%Z(d&Z)d'Z*d(Z+d)Z,d*Z-d+Z.d,Z/d-Z0d.Z1d/Z2d0Z3d1Z4d2Z5d3Z6d4Z7d5Z8d6Z9d7Z:RS(9cCs+||_||_|j|_i|_dS(N(t _transformert_blockst namespacet _namespacet_uscore_type_names(tselft transformertblocks((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt__init__(s   cCs|jjstjdn|jj|j|jj|j|jj|j|jj|j|jj|j |jj|jx|jj D]z}t |t j r|jdk r||j|j()])iittt)(tretsplittlentappend( ttype_strtresolvert top_combinertcombinertbitstfirsttseptresttargstlastseptnext(tgrab_one(sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRs4  csjj|}|S(N(R(tcreate_type_from_user_string(tidenttres(R-(sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRscs|s |St|tjrAt|dkrAtj|j|St|tjrvt|dkrv|d|_|St|tjrt|dkrtj|Stj df|S(Niiis,Too many parameters in type specification %r( R:RtListRRARt element_typetMapRtwarn(tbaseR(R(sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRs$$ $ cs:dk r-ttjr-j|_n||S(N(R=R:RtTypetis_const(RR(Rt type_node(sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyR+ss,Trailing components in type specification %rs%s: Unknown type: %rt positions( RRtresolvedR=R:RRDRmt _get_positionRk( R-RRRLR_RRtresultRtpositionttext((RRR-RRsy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_resolves"    cCs@|j|d|d|d|}|dk r<|j|_n|S(sJLike _resolve(), but attempt to preserve more attributes of original type.RRLR_N(RR=Ru(R-RRRLR_R((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_resolve_toplevel@s! cCs|jj|j}|rt|tjrE|jj|j}n-t|tjrl|j jt }nd}|j r|j Sn|j S(N( R)RiRmR:RR[tparamsR\tReturnttagsRR=R(R-tfuncRbRotpart((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRIs  cCs|j}|j}|tjjkrv|tjkrB|tjks]t|tjtj frvt j d|j qvn|tjj kr|tjkrtj|_q|tjtjtjgkrt j d|j qndS(Ns9invalid (element-type) for a GPtrArray, must be a pointersNinvalid (element-type) for a GByteArray, must be one of guint8, gint8 or gchar(t array_typeRRRt GLIB_PTRARRAYtBASIC_GIR_TYPESt POINTER_TYPESR:R~RRRRtGLIB_BYTEARRAYtTYPE_ANYt TYPE_UINT8t TYPE_INT8t TYPE_CHAR(R-tarrayRhRR((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRXs    c Cs2|jt}|r7|j|d|j||}ngt|jtjr[|jj}nC|jj}|j dk r|j j dr|j d |_ nt|jtjr|jj }nd}|jt }tj||d|jj d|jj}t|kr(|jtdk|_n t|_|jt} | rt|tjrp|j|| |} nZ|j|| |} | r|j| } |j| _| jtjkrtj| _qn| r| |_qn|jt} | r%yt| |_Wq%tt fk r!dSXn||_dS(Nit*iRuRt1(!RiR RRR:RRRtcloneRuR=tendswithRRRR!tzeroterminatedRTR tCompoundRgRdRYt directiontPARAM_DIRECTION_OUTtPARAM_TRANSFER_FULLR{tlength_param_nameRtinttsizet TypeErrorRZ( R-R_RLRhtelement_type_optionstelement_type_nodeRt array_optionstcontainer_typetlengtht paramnameRbtfixed((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRnsJ !   cCs|jt}|dkrdSt|jtjrt|dkrjtj dt|f|j dS|j |d|j|||j_ n(t|jtj r*t|dkrtj dt|f|j dS|j |d|j|||j_|j |d|j|||j_nt|jtjrt|dkrutj dt|f|j dS|j |d|j|||j_ ntj d|jf|j dS(NisQ"element-type" annotation for a list must have exactly one option, not %d optionsiisZ"element-type" annotation for a hash table must have exactly two options, not %d option(s)sS"element-type" annotation for an array must have exactly one option, not %d optionss0Unknown container %r for element-type annotation(RiR R=R:RRRRRRRRRRtkey_typet value_typeR(R-R_RLRhR((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRsF            cCs9|jtjtjgkr2|jr+tjStjStjS(N(RRtPARAM_DIRECTION_INOUTRtcaller_allocatestPARAM_TRANSFER_NONER(R-R_RL((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_get_transfer_default_params   cCs^|jtjs-|js-|jtjr4tjS|jtjrMtjS|jrZdSdS(N( tis_equivRRRt TYPE_NONERt TYPE_STRINGRttarget_fundamentalR=(R-ttypeval((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt&_get_transfer_default_returntype_basics  cCs|jj|}|s*tt||jj|}|sHt||krXtS|jr|jjdkr|j|j|StS(NsGObject.Object( R(tlookup_typenodeRtstrRVt parent_typet target_ginamet_is_gi_subclassRT(R-Rt supercls_typetclstsupercls((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRs  cCs|j}|j|}|r"|S|js/dS|jj|}t|tjrc|j|j St|tj st|tj tj fr|j dk s|jrtjSt|tjtjfrtjSt|tjr||jr|t|tjrKtjdd}|jj|}|rA|j||rAtjStjSqt|tj tj frmtjStdn)t|tjtj tj frdSdSdS(NRsGObject.InitiallyUnownedsInvalid constructor(RRRR=R(RR:RRRqtBoxedR?R@RtforeignRR~RRRDtis_constructorRFRRR(R-R_RLRtbasicRqtinitially_unowned_typetinitially_unowned((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_get_transfer_default_returns8   !cCs|jjtjs*t|jtjr1tjSt|tjrS|j||St|tj ru|j ||St|tj rtjSt|tj rtjSt |dS(N(RRRRR:tVarargsRR[RRRtFieldtPropertyR(R-R_RL((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyR| s*cCsa|r|jni}|jt}|rO|j|d|j|||_nt}d}t|krstj }nt |krctj }|t }t |dkr,|jj r#|jjr#|jj|jj } |jj| } d|jjk} t| tjtjf} | o| }q`t}q{|d} | tkrKt}q{| tkr{t}q{nt|kr{tj}n|dk r||jkr||_||_|j|||_n|jt} | rt | dkr| d}|tkrt }n||_n|j!|||t"|kr=t|_#nt$|krUt|_%nt&|kr|jtj krt|_%qt|_#n|jtj kr|jj dks|jj dkrt|_#n|r|j'r|j'|_(nt)|krt|_*n|r]|jt+}|dk r]x3|j,D]"\}}|r1||j-|ss3%s: unknown parameter %r in documentation comment%s(tsettinstance_parameterRRiR\R=R.taddRtjoinRRRAR( R-R_RRot declparamst doc_paramRbt docparamstunknowntunusedtdoc_nameR((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_apply_annotations_paramss:          cCs@|j|||j||j||j||j|dS(N(RwR>RzR0R}(R-RLRWRo((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRsscCs|s dS|jj|j}|s)dS|jjt}|r]|jj|d|_n|j|_ y|j |||jWnt k r}|GHnXdS(Ni( RRiRARhRR(RRRRRtAttributeError(R-R_RoRXRRtex((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRs cCs|j|}|jjd||jf}|j|||sHdS|jjt}|dk r|d}|tkrt }n||_ n|j |||_ |jjt }|r|j |d|j|||_ndS(Ns%s:%si(RR)RiRARwRhRR=R$R%R{R|RRR(R-R_RtprefixRoRR{R((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRs     c Csg}|j|}|jjd||jf}|r|j||t|jt|jkr|jj}xbt |jD]#\}}||d\|_ }qWqt|jdkrt j d|j qnxt |jD]\}}|r^||d\} }|rd|jjt} | r[|j| d|j|||_q[qdnd}|j|||qW|j||j|dS(Ns%s::%siisWincorrect number of parameters in comment block, parameter annotations will be ignored.(RR)RiRARwRRRzR t enumerateR\RRRRhRRRR=R.R0R}( R-R_tsignalR1RARotiRbRRAR((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRs. cCs[|j|}|dkrdS|j|||jjt}|rW|d|_ndS(Ni(RR=RwRhRiRR(R-RLRotvalue_annotation((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyR6s cCs^|dkrdSxG|jD]<}|jj|jd}|r|jr|j|_qqWdS(N(R=tmembersRRiRmRR(R-RLRotmRb((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRAs  c Cst|tjr|jj|j}|j||||rJ|dnd}|r|r|jjt }|r|d}t }xL|j D]A}|j |krt }|j |_|j||g|PqqW|stj|d|t fqqqnt S(Niis+Virtual slot %r not found for %r annotation(R:RRDR)RiRmRrR=RhRRTtvirtual_methodsRARVtinvokerRsRRk( R-RLRWRoR_tvirtual_annotationt invoker_nametmatchedtvfunc((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRIJs(    cCsIt|}x6|D].}|jj|}|s|j|qqW|S(shGiven a list of Type instances, return a new list of types with the ones that failed to resolve removed.(RCR(t resolve_typetremove(R-ttypelistt new_typelistRR((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_resolve_and_filter_type_listds   c Cset|tjr(|jj|jnt|tjrzx$|jD]}|jj|jqDW|jj|j jnt|tj r|jj|j nt|tj tj tjtjfrx3|jD]%}|jrq|jj|jqWnt|tj tj fr x|jD]V}y|jj|Wntk rTq$nX|jj|}|r$||_Pq$q$Wt|tj rtjdd|_nx$|jD]}|jj|jqWx;|jD]-}x$|jD]} |jj| jqWqWnt|tj r7|j|j|_nt|tj ra|j|j|_ntS(NRsGObject.Object(R:RRR(RNRqRxRzRR}RRRFRGR?R@RPRRt parent_chainRZRRRRRRRt interfacest prerequisitesRV( R-RLRWt parameterRXR_RqRRRb((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyR5osF'   cCsxi}x[|jjD]J}t|tjs4qnt|jj}|||<|||j (ast.Class(TextBuffer), 'try_new')iiROiN(R=RVtrsplitRR,RiR7(R-RMRLtcounttprev_split_countt componentst type_string((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_split_uscored_by_types   cCs|jjds|jr"dS|jj|j\}}||jksRt|j||rx|j||dS|j ||r|j ||dS|j ||rdSdS(sXCheck to see whether a toplevel function should be a method or constructor of some type.RON( RmRQtis_type_meta_functionR(R\R+Rt_is_constructort_set_up_constructort _is_methodt _setup_methodt_pair_static_method(R-RRat subsymbol((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyREscCs|j}t|jS(s;Given a Type(target_giname='Foo.BarBaz'), return 'bar_baz'.(t get_ginameR&RB(R-RRA((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_uscored_identifier_for_types cCs|js3|jr/tj|d|jfntS|jd}|jj|j}t |t j t j t j t jt jfs|jrtj|d|jfntS|j|jkr|jrtj|d|jfntS|jt jkr$|jr tj|d|jfntS|jjdk rU|jjjddkrUtS|js|j||}|j|stSntS(Ns %s: Methods must have parametersis8%s: Methods must have a pointer as their first parametersI%s: Methods must belong to the same namespace as the class they belong tos;%s: The first argument of methods cannot be an out-argumentRi(RzR!RRkRmRTR(RRR:RRFRGR?R@RR*R+RRRuR=Rdt_get_uscored_prefixRQRV(R-RRoRRqtuscored_prefix((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRlsD           - cCsC|j||}|jj|jdj}|j r|j|d r|j}|j|_ |jj d|_ |j j |}|j |t|d|_t|_|jj|nz|jj d|_ |jj||js/|j j |}|j |t|d|_t|_n|jj|dS(NiROi(RrR(RRzRR!RQRRAtmoved_totpopR5RmtfindRRVtmethodsRR+tfloat(R-RRoRsRqtnewfunct subsym_idx((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRm s"     cCst}d}|jd}|jj|j}t|drs|jdk rs|j|j}|rs|j}qsn|s|j |j}n|S(NiR>( RTR=RzR(RRthasattrR>RQRq(R-RRotprefix_matchesRst first_argRq((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRr/s cCs|j|}|dkrtS|\}}|dkr;tSt|tjrz|jj|||_|j j |t St|tj tj tjtjtjtjfr|j}||_|j j ||jd|j|_t StS(NRt.(RhR=RTR:RRFR+RxRAtstatic_methodsRRVRGR?R@RR~RRRt(R-RRoRRLtfuncnametnew_func((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRnCs&      cCs~|jj||j|||_|j||}|jj|t|_|j j sz|j ||j |j _ ndS(N( R+Rxt_get_constructor_nameRAt_get_constructor_classt constructorsRRVRR}R{R(R-RRot origin_node((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRkfs   cCsXd}|j|}|dkrH|jrT|jj|jj}qTn |\}}|S(N(R=RhRR(RR}R(R-RRoRRRO((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRus   cCsId}|j|}|dkr9|jrE|j}qEn |\}}|S(N(R=RhRRA(R-RRoRARRO((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRs   cCs:|jdrtSd|kr#tS|jdr6tStS(Nt_newt_new_t_newv(RRVRT(R-Rm((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyt_guess_constructor_by_names cCs|js"|j|js"tSn|jj|jj}t|t j pt|t j t j t j fo|jdk p|js|jrtj|d|jfntS|j||}|dkr|jrtj|d|jfntSt|t j p?t|t j t j t j fo?|jdk p?|jsFtS|j|jkr|jr~tj|d|jfntS|j rt|jdkr|jj|jdj}|dk r|j|jkrtSnt|t j r|}x|r|jdk r||kr#Pn|jrD|jj|j}nd}|dkrtj|d|jt|jt|jjftSqWnH||krtj|d|jt|jt|jjftStS(Ns7%s: Constructors must return an instance of their classs3Can't find matching type for constructor; symbol=%rsN%s: Constructors must belong to the same namespace as the class they belong toisGObject.ObjectsRReturn value is not superclass for constructor; symbol=%r constructed=%r return=%rsCConstructor return type mismatch symbol=%r constructed=%r return=%r(RRRmRTR(RR}RR:RRFR?R@RR<R=RRRkRR*R+RRztgi_nameRRt create_typeRV(R-RRoRqRR}R_((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRjsp !    !         cCs|js dS|j}|jj|j}x/|jD]$}t|tjr8t|_ q8q8Wx@|jD]5}d}t|j tj r|j }nB|j dk rj|jj|j }t|tj sqjqnqjt|jdkrqjn|jdj }||krqjntjj|j|}|jd|_|j||j|}|jjd||jf} |j||g| |jj|qjWx|jD]}x|jD]} | j|jkrqn| jj |jj krqnt| jt|jkrqnxOtt| jD]8} | j| j } |j| j } | | kr3q3q3q3W| j|_|jj| j} |j|g| PqWqWdS(s2Look for virtual methods from the class structure.Nis%s::%s( tglib_type_structRR(RRPR:RRRTtwritableR=RRRSRRRzR%t from_callbackRAR5tinherit_file_positionsRR)RiRsRHRRwR}trangeRIRm(R-RLt node_typet class_structRXtcallbacktfirstparam_typeRMRARotmethodRDtm_typetv_type((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRHsZ         cCs3t|tjr/|j||j|ntS(sKPass 3 is after we've loaded GType data and performed type closure.(R:RRxt_pass3_callable_callbackst_pass3_callable_throwsRV(R-RLRW((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRJ s cCsd|j}xe|D]]}|jj|j}t|tjr|jjdkrmtj|_ tj |_ qmqqWd}x|D]}|jj|j}t }t|tjr|jjdkrt}q|}q~n|dkrq~n|r|j|_tj|_ tj |_ q~|jjtjr~|jdk r~|jjdr~|j|_q~q~WdS(saCheck to see if we have anything that looks like a callback+user_data+GDestroyNotify set.sGio.AsyncReadyCallbacksGLib.DestroyNotifytdataN(sGio.AsyncReadyCallbacksGLib.DestroyNotify(RzR(RRR:RRSRtPARAM_SCOPE_ASYNCR&RR{R=RTRVR\R'R(RRRR)(R-RLRRbtargnodetcallback_paramtis_destroynotify((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyR(s6          cCsI|js dS|jd}|jjdkrE|jjt|_ndS(saCheck to see if we have anything that looks like a callback+user_data+GDestroyNotify set.NisGError**(RzRRuRuRVtthrows(R-RLt last_param((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyRLs    N(;t__name__t __module__R0RNR4RdRgRrRtR6R7RRR8RR=RRRRRRRRRRR|RRwRR.R0R>RsRRRRRRIRRR5RKRhRERqRlRmRrRnRkRRRRjRHRJRR(((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyR'&sp  8      + 9   2 '  #  O .  %  '    $  ' !    ) "  #  F C  $(-RRRRtannotationparserRRRRRRRR R R R R RRRRRRRRRRRRRRRRRRR R!R"R#R$R%tutilsR&tobjectR'(((sy/home/vagrant/ruby-gnome2.win64/gobject-introspection/vendor/local/lib/gobject-introspection/giscanner/maintransformer.pyts "4