0A7hۛ&dZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl ZddlZddlZddlZddlmZddlZddlmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$ddl%m&Z&ddl'm(Z(ddl)m*Z*ddl+m,Z,dd l-m.Z.ej^d Z0ej^d ejbZ2ej^d Z3ej^d ejbjhZ5djmZ7gdZ8dZ9dZ:e:jwdjvejxeZ=dZ>dZ?dZ@d1dZAd1dZBd1dZCdedfdZDdZEej^dejbZF eEdZGGddZHGd d!eHZIGd"d#eZJej^d$jZLd%ZMd&ZNd2d'ZOd(ZPGd)d*ZQGd+d,e jZSejjfd-ZVd.ZWeOe9eVZVd/ZXd0ZYy)3z$PyPI and direct package downloading.Nwraps) CHECKOUT_DIST Distribution BINARY_DISTnormalize_path SOURCE_DIST Environmentfind_distributions safe_name safe_version to_filename Requirement DEVELOP_DISTEGG_DIST parse_version)log)DistutilsError) translate)Wheelunique_everseenz^egg=([-A-Za-z0-9_.+!]+)$zhref\s*=\s*['"]?([^'"> ]+)z([^<]+)\n\s+\(md5\)z([-+.a-z0-9]{2,}):z.tar.gz .tar.bz2 .tar .zip .tgz) PackageIndexdistros_for_urlparse_bdist_wininstinterpret_distro_namez  && CG I  s 4/4c8|j}d\}}}|jdro|jdr|dd}d}nV|jddr |d d }|dd}d}n7|jd r|dd }d }n|jddr |d d }|dd}d }|||fS)z=Return (base,pyversion) or (None,None) for possible .exe name)NNN.exez .win32.exeNiwin32z .win32-pyiiz.win-amd64.exeiz win-amd64z .win-amd64-pyi)lowerendswith startswith)namer+basepy_verplats r%rrNs JJLE)D&$ ~~f >>, ':DD   k3 /"R[F:DD ^^, -:DD   os 3"R[F:DD  cdtjj|}|\}}}}}}tjj|j dd}|dk(r6|dk(r1tjj|j dd}d|vr|j dd\}}||fS)N/zsourceforge.netdownload#)urllibr!urlparseunquotesplit) urlpartsschemeserverpath parametersqueryfragmentr/s r%egg_info_for_urlrFfs LL ! !# &E8=5FFD*eX <<   3 3 4D ""tz'9||##DJJsOB$78 d{C+h >r2c#Kt|\}}t|||D]}||rDtj|}|r,t ||j d|t D]}|yyyw)zEYield egg or source distribution objects that might be found at a URLr9) precedenceN)rFdistros_for_location EGG_FRAGMENTmatchrgroupr)r>metadatar/rEdistrKs r%rrqs}%c*ND($S$9 ""8, -U[[^X-    sA,A.c&|jdr|dd}|jdrd|vrtj|||gS|jdrLd|vrHt|}|j sgSt||j |j tdzgS|jd r%t|\}}}|t||||t|StD]1}|j|s|dt| }t|||cSgS) z:Yield egg or source distribution objects based on basename.egg.zipNr*z.egg-z.whlr9)location project_nameversionrHr() r,r from_locationr is_compatiblerSrTrrrr EXTENSIONSlen)rRbasenamerMwheelwin_baser0platformexts r%rIrIs+$CR= SH_**8XxHII SH_h""$I !"// #a<     %8%B"&(  ((Hfk8  G   S ! 3s8),H(8XF FG Ir2chtt|tjj ||S)zEYield possible egg or source distribution objects based on a filename)rIrosrBrY)filenamerMs r%distros_for_filenameras* x "''"2"28"z(interpret_distro_name..sKAbhh|Q7Ks "Nr9) py_versionrHr\)r=anyrangerXisdigitrjoin)rRrYrMrirHr\r?rfs r%rrs NN3 E #KqrKK3u:  8BQ<   !  J  r qr s AB!AB!c.tfd}|S)zs Wrap a function returning an iterable such that the resulting iterable only ever yields unique items. c&t|i|SNr)argskwargsfuncs r%wrapperzunique_values..wrapperstT4V455r2r)rsrts` r% unique_valuesrus"  4[66 Nr2z3<([^>]*\srel\s{0,10}=\s{0,10}['"]?([^'" >]+)[^>]*)>c #Ktj|D]}|j\}}tt t j |jjd}d|vsd|vs_tj|D]<}tjj|t|jd>dD]l}|j|}|dk7stj!||}|s3tjj|t|jdnyw)zEFind rel="homepage" and rel="download" links in `page`, yielding URLs,homepager6r9)z Home PagezDownload URLr5N)RELfinditergroupssetmapstrstripr+r=HREFr:r!urljoin htmldecoderLfindsearch)r>pagerKtagrelrelsposs r%find_external_linksrsd#L<<>S3syy#))+"3"3C"89:  t!3s+ Lll**3 5;;q>0JKK L L5Liin "9KKc*Ell**3 5;;q>0JKK LsA4D?7A1D?)D?=D?c"eZdZdZdZdZdZy)ContentCheckerzP A null content checker that defines the interface for checking content cy)z3 Feed a block of data to the hash. Nselfblocks r%feedzContentChecker.feeds r2cy)zC Check the hash. Return False if validation fails. Trrs r%is_validzContentChecker.is_validsr2cy)zu Call reporter with information about the checker (hash name) substituted into the template. Nr)rreportertemplates r%reportzContentChecker.reports r2N)__name__ __module__ __qualname____doc__rrrrr2r%rrs  r2rcXeZdZejdZdZedZdZ dZ dZ y) HashCheckerzK(?Psha1|sha224|sha384|sha256|sha512|md5)=(?P[a-f0-9]+)cT||_tj||_||_yrp) hash_namehashlibnewhashexpected)rrrs r%__init__zHashChecker.__init__s "KK *   r2ctjj|d}|s tS|jj |}|s tS|di|j S)z5Construct a (possibly null) ContentChecker from a URLr5r)r:r!r;rpatternr groupdict)clsr>rErKs r%from_urlzHashChecker.from_urls^<<((-b1!# # ""8,!# #'U__&''r2c:|jj|yrp)rupdaters r%rzHashChecker.feed s r2cP|jj|jk(Srp)r hexdigestrrs r%rzHashChecker.is_valid#syy""$ 55r2c0||jz}||Srp)r)rrrmsgs r%rzHashChecker.report&s'}r2N) rrrrdcompilerr classmethodrrrrrr2r%rr s?bjj #G ! (( 6r2rc@eZdZdZ d'fd ZfdZd(dZd(dZd(dZdZ dZ d Z d Z d Z d)d Zd Zd)fd ZdZdZdZdZdZ d*dZd+dZdZdZdZdZd)dZedZdZedZ dZ!dZ"d Z#d!Z$d"Z%ed#Z&d$Z'd%Z(d&Z)xZ*S),rz;A distribution index that scans web pages for download URLscVt||i||dd|jd z|_i|_i|_i|_tjdjtt|j|_ g|_tj j"|_y)Nr4|)superrr, index_url scanned_urls fetched_urls package_pagesrdrrmr}rrKallowsto_scanr:requesturlopenopener)rrhosts ca_bundle verify_sslrqkw __class__s r%rzPackageIndex.__init__.s $%"%"S)Fy/A/A#/F+F%GGjj#i*?!@AGG  nn,, r2cl t|jt||S#t$rYywxYwrp)rrT Exceptionradd)rrNrs r%rzPackageIndex.add@s9  $,, 'w{4     s ' 33c ||jvr|syd|j|<t|s|j|ytt |}|r$|j |sy|j d||s|r||jvr tt|j|y|j |sd|j|<y|jd|d|j|<d}|j|||z}|yt|tjjr-|j dk(r|jd|j"zd|j|j$<d|j&j)d d j+vr|j-y|j$}|j/}t|t0sXt|tjjrd }n|j&j3d xsd }|j5|d }|j-t6j9|D]K} tj:j=|t?| jAd} |jC| M|jE|jFr$tI|dddk7r|jK||}yyy)zheadersgetr+closereadr~ get_paramdecoderrzr!rrrL process_urlr-rgetattr process_index) rr>retrievediststmplfr/rrrKlinks r%rzPackageIndex.process_urlIsV $## #H !%##  ! !# & -.E{{3' +S1 C4+<+<$< TXXu% & {{3%)D  c "  ,$!%#M MM#tcz * 9  a// 0QVVs] II01558 9#'!%% ~r:@@B B GGI uuvvx$$!V\\334#))--i8EI;;w1D  ]]4( #E<<''jQ.HID   T " # >>$.. )ga.F#.M%%c40D/N )r2ctjj|s|jd|ytjj |rk|sitjj |}tj |D]2}|jtjj||d4t|}|r2|jd|tt|j|yy)Nz Not found: %sTz Found: %s)r_rBexistswarnisdirrealpathlistdirrrmrarrr}r)rfnnestedrBitemrs r%rzPackageIndex.process_filename~sww~~b! IIor *  77== V77##B'D 4( F%%bggll4&>E F%R(  JJ{B ' TXXu% & r2ct|}|xr"|jdjdk(}|s1|jtj j |dryd}|rt||z|j||y)Nr9fileTz Note: Bypassing %s (disallowed host; see https://setuptools.pypa.io/en/latest/deprecated/easy_install.html#restricting-downloads-with-allow-hosts for details). ) rrLr+rr:r!r;rr)rr>fatalsis_filers r%rzPackageIndex.url_oks} sO4 ((*f4 dkk&,,"7"7".sF D) ~~k*5M  s9;)filterr_rBrr itertoolsstarmap scan_egg_link)r search_pathdirs egg_linkss r%scan_egg_linkszPackageIndex.scan_egg_linkssBbggmm[1  Y  t119 =>r2c ttjj||5}t t dt tj|}dddtdk7ry|\}}ttjj||D]C}tjj|g||_ t|_ |j|Ey#1swYxYw)Nrh)openr_rBrmrrr}r~rrXr rRr rHr)rrBr raw_lineslinesegg_path setup_pathrNs r%rzPackageIndex.scan_egg_links "'',,tU+ , B c#))Y&?@AE B u:? $*&rww||D('CD DGGLL66DM)DO HHTN  B Bs .C$$C-c d}|j|js|Stttj j |t|jdjd}t|dk7sd|dvr|St|d}t|d}d|jj|ji|<t|t|fS)N)NNr4rhr8r9rT)r-rrr}r:r!r<rXr=r r r setdefaultr+r)rrNO_MATCH_SENTINELr?pkgvers r%_scanzPackageIndex._scans&t~~.$ $S--tC4G4I/J/P/PQT/UVW u:?cU1Xo$ $a!58$?C%%ciik26t<3S!111r2c tj|D]J} |jtjj |t |jdL|j|\}}|syt||D]S}t|\}}|jdr!|s|r |d|d|z }n|j||j|Utjd|S#t$rYwxYw)z#Process the contents of a PyPI pager9r.pyz#egg=rQc.d|jdddzS)Nz%sr9rh)rL)ms r%z,PackageIndex.process_index..s2QWWQ15EEr2)rrzr r:r!rrrLr"rrFr,need_version_infoscan_urlPYPI_MD5sub) rr>rrKr r new_urlr/frags r%rzPackageIndex.process_indexs]]4( E  6<<//Z A5OPQ  ::c?S+35 #G)'2JD$}}U#DsC88G**3/ MM' " #|| Et  %  sAC33 C?>C?c(|jd|y)NzPPage at %s links to .py file(s) without version info; an index scan is required.)scan_allrr>s r%rzPackageIndex.need_version_infos   r2c|j|jvr&|r|j|g||jd|j |jy)Nz6Scanning index of all packages (this may take a while))rrrrrrrrqs r%rzPackageIndex.scan_allsG >>!2!2 2 #%% IIN O dnn%r2c|j|j|jzdz|jj |j s+|j|j|j zdz|jj |j s|j|t|jj |j dD]}|j|y)Nr4r) rr unsafe_namerrkeyrSnot_found_in_indexr)r requirementr>s r% find_packageszPackageIndex.find_packagess dnn{'>'>>DE!!%%koo6 MM$..;+C+CCcI J!!%%koo6  # #K 0**..{CD C MM#  r2c|j|j|||jD]}||vr|cS|jd||tt |||S)Nz%s does not match %s)prescanr$r!rrrobtain)rr# installerrNrs r%r'zPackageIndex.obtainsh  ;') BD{" JJ-{D A B\4/ YGGr2c0|j|jd|z|jsg|jt j |t |jjdtjj|dy)z- checker is a ContentChecker zValidating %%s checksum for %sz validation failed for z; possible download problem?N) rrrrr_unlinkrrr.rBrY)rcheckerr`tfps r% check_hashzPackageIndex.check_hash su tzz#Ch#NO! IIK IIh  <<$$bgg&6&6x&@B "r2c|D]k}|j0t|r%|jdstt |r|j |Q|jj |my)z;Add `urls` to the list that will be prescanned for searchesNfile:)rrr-rrrappend)rurlsr>s r%add_find_linkszPackageIndex.add_find_linkss] )C $!#>>'*,- c" ##C( )r2c||jr)tt|j|jd|_y)z7Scan urls scheduled for prescanning (e.g. --find-links)N)rrr}rrs r%r&zPackageIndex.prescan's' << T]]DLL1 2 r2c||jr|jd}}n|jd}}|||j|j y)Nz#Couldn't retrieve index page for %rz3Couldn't find index page for %r (maybe misspelled?))r!rrr r)rr#methrs r%r"zPackageIndex.not_found_in_index-sJ    #H#D ED S+))* r2cZt|tst|}|rF|j||}t |\}}|j dr|j |||}|Stjj|r|St|}t|j||ddS)aLocate and/or download `spec` to `tmpdir`, returning a local path `spec` may be a ``Requirement`` object, or a string containing a URL, an existing local filename, or a project/version requirement spec (i.e. the string form of a ``Requirement`` object). If it is the URL of a .py file with an unambiguous ``#egg=name-version`` tag (i.e., one that escapes ``-`` as ``_`` throughout), a trivial ``setup.py`` is automatically created alongside the downloaded file. If `spec` is a ``Requirement`` object or a string containing a project/version requirement spec, this method returns the location of a matching distribution (possibly after downloading it to `tmpdir`). If `spec` is a locally existing file or directory name, it is simply returned unchanged. If `spec` is a URL, it is downloaded to a subpath of `tmpdir`, and the local filename is returned. Various errors may be raised if a problem occurs during downloading. rrRN) rrr _download_urlrFr, gen_setupr_rBrr&rfetch_distribution)rr#tmpdirr@foundr/rEs r%r6zPackageIndex.download8s$$ ,%F**48!1$!7h==' NN5(FCE % ,T2t..tV.findxs{CGG  $??l2:7* D )* s{U;(F(Tf*-- v>C-0D*ww~~d&<&<=#  $r2z:No local packages or working download links found for %s%sza source distribution of rzBest match: %s)rRrp)rr&r$rrcloner>) rr#r: force_scanrErC local_indexrNrrDs ` ` `` @r%r9zPackageIndex.fetch_distributionZs4 $k2 $ $,  LLN   { + $D / [1D <||'  $D <   { + $D < IIL77=2  II& -::t'='=:> >r2cH|j||||}| |jSy)a3Obtain a file suitable for fulfilling `requirement` DEPRECATED; use the ``fetch_distribution()`` method now instead. For backward compatibility, this routine is identical but returns the ``location`` of the downloaded distribution instead of a distribution object. N)r9rR)rr#r:rGrErNs r%fetchzPackageIndex.fetchs-&&{FJO  == r2c tj|}|xr6t||jddDcgc]}|jr|c}xsg}t |dk(rBt jj|}t jj||k7rwt jj||}t jj|r t jj||stj|||}tt jj|dd5} | j!d|dj"d|djdt jj%|ddddd|S|rt'd |d |t'd cc}w#1swY|SxYw) Nr9zsetup.pywz(from setuptools import setup setup(name=rz , version=z, py_modules=[z]) z9Can't unambiguously interpret project/version identifier zI; any dashes in the name or version should be escaped using underscores. zpCan't process plain .py files without an '#egg=name-version' suffix to enable automatic setup script generation.)rJrKrrLrTrXr_rBrYdirnamermrsamefileshutilcopy2rwriterSsplitextr) rr`rEr:rKdrrYdstrs r%r8zPackageIndex.gen_setups""8,  /xQN99    u:?ww''1Hwwx(F2ggll684s+0@0@30OLL3/"Hbggll6:6<  a--a((((215  O  &.u6  !G K$ OsGAGGi c>|jd|d} tj|}|j|}t |t j jr(td|d|jd|j|j}d}|j}d}d|vr?|jd} ttt| }|j!|||||t#|d 5} |j%|} | r=|j'| | j)| |d z }|j!|||||nnR|j+||| ddd||r|j-SS#1swYxYw#|r|j-wwxYw) NzDownloading %szCan't download :  rr5zcontent-lengthzContent-Lengthwbr9)rrrrrr:rrrrr dl_blocksizeget_allmaxr}int reporthookrrrrQr-r) rr>r`fpr+rblocknumbssizesizesr,rs r% _download_tozPackageIndex._download_tosv "C(  !**3/Gs#B"fll445$25rwwGggiGH""BD7*(893sE?+XxTBh% 8GGBKE U+ %( A XxTJ37 8  8 8 s%C!F7A'E; F;FFFcyrpr)rr>r`r_blksizeras r%r]zPackageIndex.reporthook s r2c |jdr t|S t||jS#tt j jf$rh}dj|jDcgc] }t|ncc}wc}}|r|j||nt|d||Yd}~yd}~wtjj$r }|cYd}~Sd}~wtjj $rE}|r|j||j"ntd|d|j"|Yd}~yd}~wt j j$$rD}|r|j||j&nt|d|j&|Yd}~yd}~wt j j(t*jf$r1}|r|j||ntd|d||Yd}~yd}~wwxYw)Nr/rWzDownload error for rVz7 returned a bad status line. The server might be down, )r- local_openopen_with_authrr"httpclient InvalidURLrmrqr~rrr:rrURLErrorreason BadStatusLineline HTTPExceptionsocket)rr>warningvargrs r%rzPackageIndex.open_urls >>' "c? " T!#t{{3 3DKK223 B((7CH778C '3'$S%9:A(||%% H||$$  '188,$36A- {{((  '166*$"%qvv/+  ))6<<8 T '1%$C%KLRSS& TsW4#HB:0B 3B:: HC!H! H;E H!:F  0H'G<<Hc>t|\}}|r,d|vr*|jddjdd}d|vr'nd}|jdr|dd}tjj ||}|j t|std ||S) aB >>> import pathlib >>> du = PackageIndex._resolve_download_filename >>> root = getfixture('tmp_path') >>> url = 'https://files.pythonhosted.org/packages/a9/5a/0db.../setuptools-78.1.0.tar.gz' >>> str(pathlib.Path(du(url, root)).relative_to(root)) 'setuptools-78.1.0.tar.gz' Ensures the target is always in tmpdir. >>> url = 'https://anyhost/%2fhome%2fuser%2f.ssh%2fauthorized_keys' >>> du(url, root) Traceback (most recent call last): ... ValueError: Invalid filename... z...\___downloaded__rPNr*zInvalid filename ) rFreplacer,r_rBrmr-r~r")r>r:r.rEr`s r%_resolve_download_filenamez'PackageIndex._resolve_download_filename0s$*#.h $,||D#.66tSA$,$D == $9D77<<-""3v;/0 ;< <r2cr|j||}|j||xs|j||S)z2 Determine the download filename. )r{ _download_vcs_download_other)rr>r:r`s r%r7zPackageIndex._download_urlTs;223?!!#x0WD4H4Hh4WWr2ctjj|j}|j d\}}}t ddgdgt |zz}tt|h|zdS)a  >>> rvcs = PackageIndex._resolve_vcs >>> rvcs('git+http://foo/bar') 'git' >>> rvcs('hg+https://foo/bar') 'hg' >>> rvcs('git:myhost') 'git' >>> rvcs('hg:myhost') >>> rvcs('http://foo/bar') +svngithgN) r:r!urlsplitr@ partitionr|boolnextiter)r>r@preseppostalloweds r% _resolve_vcszPackageIndex._resolve_vcs[sj&&s+22))#.S$uenvS '99:D#)400r2c |j|}|sy|dk(rtd||jd\}}}|j|\}}|j d|d|d|t j |dd||gt|d |d d|g|d |d d d |dg}|,|j d|t j |||S)Nrz/Invalid config, SVN download is not supported: r8zDoing z clone from z to rFz--quietz-Ccheckoutz--cwdupz-rz-q)rrz Checking out )rrr_vcs_split_rev_from_urlr subprocess check_calldict)rr> spec_filenamevcsr`rxrev co_commandss r%r}zPackageIndex._download_vcsns$  %< A#G '005!Q//4S F3%|C5XJ?@sGYXFGdHj)SAWhdD#tD  ? II cU+ ,  ! !+c"2 3r2c2tjj|j}|dk(rFtjj tjj |jS|j|d|j||S)NrT) r:r!rr@r url2pathnamer;rBr_attempt_download)rr>r`r@s r%r~zPackageIndex._download_otherso&&s+22 V >>..v||/D/DS/I/N/NO O C%%c844r2c(|j|dy)NT)rrs r%rzPackageIndex.scan_urls d#r2c|j||}d|jddjvr|j|||S|S)Nrrr)rcrr+_invalid_download_html)rr>r`rs r%rzPackageIndex._attempt_downloadsJ##C2 W[[4::< <..sGXF FOr2cHtj|td|)NzUnexpected HTML page found at )r_r*r)rr>rr`s r%rz#PackageIndex._invalid_download_htmls! (=cUCDDr2cLtjj|}|jj ddd}|j j d\}}}|jd\}}}|r||fn|df\}} |j||dj} | | fS) a Given a possible VCS URL, return a clean URL and resolved revision if any. >>> vsrfu = PackageIndex._vcs_split_rev_from_url >>> vsrfu('git+https://github.com/pypa/setuptools@v69.0.0#egg-info=setuptools') ('https://github.com/pypa/setuptools', 'v69.0.0') >>> vsrfu('git+https://github.com/pypa/setuptools#egg-info=setuptools') ('https://github.com/pypa/setuptools', None) >>> vsrfu('http://foo/bar') ('http://foo/bar', None) rr9r5r8@Nr)r@rBrE) r:r!rr@r=rBr rpartition_replacegeturl) r>r? clean_schemeno_fragment_pathrxrrr clean_pathrresolveds r%rz$PackageIndex._vcs_split_rev_from_urls %%c*||))#q1"5 "'!5!5c!:!Q)44S9S$),3+4, C>> " &( }r2c0tj|g|yrp)rrrs r%rzPackageIndex.debugs #r2c0tj|g|yrp)rrrs r%rzPackageIndex.info tr2c0tj|g|yrp)rrrs r%rzPackageIndex.warnrr2)zhttps://pypi.org/simple/)*NT)Frp)FFFN)FF)+rrrrrrrrrrrr rrrr$r'r-r2r&r"r6r9rJr8rYrcr]r staticmethodr{r7rr}r~rrrrrrr __classcell__rs@r%rr+sE- -$!31j'  ? 2  : & H  )  PLM?^ ,\L"H  TD!!FX11$25$E>r2rz!&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?cN|jd}tj|S)Nr)rLrunescape)rKwhats r% decode_entityrs ;;q>D == r2c"tt|S)a Decode HTML entities in the given text. >>> htmldecode( ... 'https://../package_name-0.1.2.tar.gz' ... '?tokena=A&tokenb=B">package_name-0.1.2.tar.gz') 'https://../package_name-0.1.2.tar.gz?tokena=A&tokenb=B">package_name-0.1.2.tar.gz' ) entity_subr)texts r%rrs mT **r2cfd}|S)Ncfd}|S)Nctj}tj |i|tj|S#tj|wxYwrp)rqgetdefaulttimeoutsetdefaulttimeout)rqrr old_timeoutrstimeouts r%_socket_timeoutz@socket_timeout.._socket_timeout.._socket_timeoutsN 224K  $ $W - 6T,V,((5((5s A A r)rsrrs` r%rz'socket_timeout.._socket_timeouts 6r2r)rrs` r%socket_timeoutrs  r2ctjj|}|j}t j |}|j }|jddS)a9 Encode auth from a URL suitable for an HTTP header. >>> str(_encode_auth('username%3Apassword')) 'dXNlcm5hbWU6cGFzc3dvcmQ=' Long auth strings should not cause a newline to be inserted. >>> long_auth = 'username:' + 'password'*10 >>> chr(10) in str(_encode_auth(long_auth)) False  r)r:r!r<encodebase64 b64encoderrz)authauth_s auth_bytes encoded_bytesencodeds r% _encode_authrsR\\ ! !$ 'FJ$$Z0M""$G ??4 $$r2c"eZdZdZdZdZdZy) Credentialz: A username/password pair. Use like a namedtuple. c ||_||_yrpusernamepassword)rrrs r%rzCredential.__init__s    r2c#DK|j|jywrprrs r%__iter__zCredential.__iter__ smmmms cdt|zS)Nz%(username)s:%(password)s)varsrs r%__str__zCredential.__str__s*T$Z77r2N)rrrrrrrrr2r%rrs!8r2rc:eZdZfdZedZdZdZxZS) PyPIConfigc0tjgdd}t| |tj j tj jdd}tj j|r|j|yy)z% Load from ~/.pypirc )rr repositoryr~z.pypircN) rfromkeysrrr_rBrm expanduserrr)rdefaultsrcrs r%rzPyPIConfig.__init__sf==!GL " WW\\"'',,S19 = 77>>"  IIbM r2c|jDcgc]$}|j|djr|&}}tt |j |Scc}w)Nr)sectionsrrrr}_get_repo_cred)rsectionsections_with_repositoriess r%creds_by_repositoryzPyPIConfig.creds_by_repositorys_ ==?& xx.446 & "& C++-GHII & s)Ac|j|dj}|t|j|dj|j|djfS)Nrrr)rrr)rrrepos r%rzPyPIConfig._get_repo_cred(s]xx.446Z HHWj ) / / 1 HHWj ) / / 1   r2cr|jjD]\}}|j|s|cSy)z If the URL indicated appears to be a repository defined in this config, return the credential for that repository. N)ritemsr-)rr>rcreds r%find_credentialzPyPIConfig.find_credential/s8 !% 8 8 > > @  J~~j)  r2) rrrrpropertyrrrrrs@r%rrs( JJ r2rctjj|}|\}}}}}}|jdrtj j d|dvrt|\} } nd} | sJtj|} | r/t| } | j|f} tjdg| | rgdt| z} | ||||f} tjj| }tj j#|}|j%d| ntj j#|}|j%dt&||}| rftjj|j(\}}}}}}||k(r1| k(r,||||||f} tjj| |_|S) z4Open a urllib2 request, handling HTTP authentication:znonnumeric port: '')rihttpsNz*Authenticating as %s for %s (from .pypirc)zBasic Authorizationz User-Agent)r:r!r;r,rirjrk _splituserrrr~rrrr urlunparserRequest add_header user_agentr>)r>rparsedr@netlocrBparamsrDrraddressrrr?rrr^s2h2path2param2query2frag2s r%rhrh9s\\ " "3 'F06-FFD&%skk$$%:;; """6* g |++C0 t9D==#%D HHA ID I ,t,,vud:,,))%0..((1?D1..((- |Z0 B 06||/D/DRVV/L,Bvvu  'user[:passwd]', 'host[:port]'.rN)r)hostuserdelims r%rrhs0,D%Dd **td **r2c|Srpr)r>s r% fix_sf_urlrss Jr2ctjj|\}}}}}}tjj |}t j j|rtjj|S|jdrt j j|rg}t j|D]} t j j|| } | dk(r't| d5} | j} dddnkt j j| r| dz } |jdj!| d} | j!|dj| } d \}}nd \}}} d d i}t#j$ }tj&j)|||||S#1swYxYw)z7Read a local path, with special support for directoriesr4z index.htmlrNz{name})r.zB{url}{files}r)r>files)OK)rzPath not foundz Not foundrz text/html)r:r!r;rrr_rBisfilerr,rrrmrrr0formatioStringIOrr)r>r@rArBparamrDrr`rrfilepathr^bodyrstatusmessager body_streams r%rgrgws/5||/D/DS/I,FFD%~~**40H ww~~h~~%%c** s  h 7H% @Aww||Ha0HL (C(%B779D%x(S LL6==1=E F @X ;;3dii.>;?D# B{+G++d#K << ! !#vw MM#%%s ?G  G rp)r)Zrsysrr_rdr rOrqrrr configparserr http.clientri urllib.parser:urllib.request urllib.error functoolsrr pkg_resourcesrrrrr r r r r rrrrr distutilsrdistutils.errorsrfnmatchrsetuptools.wheelr setuptools.extern.more_itertoolsrrrJIrrrKrr=rW__all___SOCKET_TIMEOUT_tmplr  version_inforr&rrFrrIrarruryrrrrrrrrrrrRawConfigParserrrrrhrrrgrr2r%r(s*    +"<rzz67 rzz3RTT: 2::J RZZ,bdd 3 9 9 . 4 4 6  F \\ W^^S-- .: 0  F.2kTXD bjjKRTTR LL$2.BY ;Y |RZZ< = A A  + %*88"$--$N &~~55+^+10@Nr2