o Cf@sdZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZddlZddlZddlmZddlZddlmZmZmZmZmZmZmZmZm Z m!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/e0d Z1e0d ej2Z3e0d Z4e0d ej2j5Z6d7Z8gdZ9dZ:dZ;e;jddZ?ddZ@ddZAdBddZBdBddZCdBddZDdedfd d!ZEd"d#ZFe0d$ej2ZGeFd%d&ZHGd'd(d(ZIGd)d*d*eIZJGd+d,d,eZKe0d-jLZMd.d/ZNd0d1ZOdCd2d3ZPd4d5ZQGd6d7d7ZRGd8d9d9e jSZTejUjVfd:d;ZWdd?ZYd@dAZZdS)Dz#PyPI and direct package downloadingNwraps) 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_namezrS)filenamerHr#r#r$distros_for_filenamesrZc cs~|d}|stdd|ddDrdStdt|dD]}t||d|d|d||d|||dVq dS)zGenerate alternative interpretations of a source distro name Note: if `location` is a filesystem filename, you should call ``pkg_resources.normalize_path()`` on it before passing it to this routine! rKcss|] }td|VqdS)z py\d\.\d$N)rerF).0pr#r#r$ sz(interpret_distro_name..Nr5) py_versionrCrV)r9anyrangerRrjoin)rLrSrHr`rCrVr;r]r#r#r$rs $ rcstfdd}|S)zs Wrap a function returning an iterable such that the resulting iterable only ever yields unique items. cst|i|SNr)argskwargsfuncr#r$wrapperszunique_values..wrapperr)rhrir#rgr$ unique_valuessrjz3<([^>]*\srel\s{0,10}=\s{0,10}['"]?([^'" >]+)[^>]*)>c cst|D]2}|\}}tttj|d}d|vs#d|vr8t |D]}t j |t |dVq(qdD] }||}|dkr[t ||}|r[t j |t |dVq;dS)zEFind rel="homepage" and rel="download" links in `page`, yielding URLs,homepager2r5)z Home PagezDownload URLr1N)RELfinditergroupssetmapstrstripr)r9HREFr6rurljoin htmldecoderGfindsearch)r:pagerFtagrelrelsposr#r#r$find_external_linkss    r~c@(eZdZdZddZddZddZdS) ContentCheckerzP A null content checker that defines the interface for checking content cCdS)z3 Feed a block of data to the hash. Nr#selfblockr#r#r$feedzContentChecker.feedcCr)zC Check the hash. Return False if validation fails. Tr#rr#r#r$is_validrzContentChecker.is_validcCr)zu Call reporter with information about the checker (hash name) substituted into the template. Nr#)rreportertemplater#r#r$reportszContentChecker.reportN)__name__ __module__ __qualname____doc__rrrr#r#r#r$rs  rc@sBeZdZedZddZeddZddZ dd Z d d Z d S) HashCheckerzK(?Psha1|sha224|sha384|sha256|sha512|md5)=(?P[a-f0-9]+)cCs||_t||_||_dSrd) hash_namehashlibnewhashexpected)rrrr#r#r$__init__s  zHashChecker.__init__cCsBtj|d}|s tS|j|}|stS|di|S)z5Construct a (possibly null) ContentChecker from a URLr1Nr#)r6rr7rpatternrx groupdict)clsr:rArFr#r#r$from_urls zHashChecker.from_urlcCs|j|dSrd)rupdaterr#r#r$rzHashChecker.feedcCs|j|jkSrd)r hexdigestrrr#r#r$rrzHashChecker.is_validcCs||j}||Srd)r)rrrmsgr#r#r$rs zHashChecker.reportN) rrrr[compilerr classmethodrrrrr#r#r#r$rs   rcsbeZdZdZ  dPddZfdd ZdQd d ZdQd dZdQddZddZ ddZ ddZ ddZ ddZ dRddZddZdRfdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Z dSd+d,ZdTd-d.Zd/d0Zd1Zd2d3Zd4d5ZdRd6d7Zd8d9Zed:d;Zdd?Z!d@dAZ"dBdCZ#dDdEZ$dFdGZ%edHdIZ&dJdKZ'dLdMZ(dNdOZ)Z*S)Urz;A distribution index that scans web pages for download URLshttps://pypi.org/simple/*NTcOsrtj|g|Ri||dd|d |_i|_i|_i|_td t t |j |_ g|_tjj|_dS)Nr0|)r rr* index_url scanned_urls fetched_urls package_pagesr[rrcrqrrFallowsto_scanr6requesturlopenopener)rrhosts ca_bundle verify_sslrekwr#r#r$rszPackageIndex.__init__cs0zt|jWn tyYdSwt|Srd)rrN Exceptionsuperadd)rrI __class__r#r$r*s   zPackageIndex.addFc Cs||jvr |s dSd|j|<t|s||dStt|}|r.||s(dS|d||s7|r7||jvrAtt|j |dS||sMd|j|<dS| d|d|j|<d}| |||}|durhdSt |t jjr||jdkr|| d|jd|j|j<d|jd d vr|dS|j}|}t |tst |t jjrd }n|jd pd }||d }|t|D]} t j|t| d} |!| q|"|j#rt$|dddkr|%||}dSdSdS)zexistswarnisdirrealpathlistdirrrcrZrrrqr)rfnnestedr>itemrr#r#r$rhs    zPackageIndex.process_filenamecCs`t|}|o|ddk}|s|tj|drdSd}|r(t|||||dS)Nr5fileTzN Note: Bypassing %s (disallowed host; see http://bit.ly/2hrImnY for details). ) rrGr)rr6rr7rr)rr:fatalsis_filerr#r#r$rxs zPackageIndex.url_okcCs2ttjj|}dd|D}tt|j|dS)Ncss2|]}t|D] }|dr ||fVq qdS)z .egg-linkN)rXrr*)r\r>entryr#r#r$r^s z.PackageIndex.scan_egg_links..)filterrXr>rr itertoolsstarmap scan_egg_link)r search_pathdirs egg_linksr#r#r$scan_egg_linkss zPackageIndex.scan_egg_linkscCsttj||}ttdttj|}Wdn1swYt |dkr,dS|\}}t tj||D]}tjj|g|R|_ t |_ ||q9dS)Nr_)openrXr>rcrrrqrrrsrRr rLrrCr)rr>r raw_lineslinesegg_path setup_pathrIr#r#r$rs  zPackageIndex.scan_egg_linkcCsd}||js |Stttjj|t|jdd}t|dks)d|dvr+|St |d}t |d}d|j | i|<t|t|fS)N)NNr0r_r4r5rT)r+rrrqr6rr8rRr9r r r setdefaultr)r )rrNO_MATCH_SENTINELr;pkgverr#r#r$_scans   zPackageIndex._scanc Cst|D]}z|tj|t|dWqty!Yqw||\}}|s-dSt ||D]$}t |\}}| drQ|sQ|rL|d||f7}n| || |q2tdd|S)z#Process the contents of a PyPI pager5r.pyz #egg=%s-%scSsd|dddS)Nz%sr5r_)rG)mr#r#r$sz,PackageIndex.process_index..)rtrnrr6rrurvrGr r~rBr*need_version_infoscan_urlPYPI_MD5sub) rr:ryrFrrnew_urlr-fragr#r#r$rs&"    zPackageIndex.process_indexcCs|d|dS)NzPPage at %s links to .py file(s) without version info; an index scan is required.)scan_allrr:r#r#r$rszPackageIndex.need_version_infocGs<|j|jvr|r|j|g|R|d||jdS)Nz6Scanning index of all packages (this may take a while))rrrrrrrrer#r#r$rs zPackageIndex.scan_allcCsz||j|jd|j|js||j|jd|j|js)||t|j|jdD]}||q3dS)Nr0r#) rr unsafe_namerrkeyrMnot_found_in_indexr)r requirementr:r#r#r$ find_packagess  zPackageIndex.find_packagescsR|||||jD]}||vr|S|d||qtt|||S)Nz%s does not match %s)prescanrrrrrobtain)rr installerrIrr#r$rs zPackageIndex.obtaincCsL||jd||s$|t|td|jjtj |fdS)z- checker is a ContentChecker zValidating %%s checksum for %sz7%s validation failed for %s; possible download problem?N) rrrrrXunlinkrrr,r>rS)rcheckerrYtfpr#r#r$ check_hashs zPackageIndex.check_hashcCsN|D]"}|jdust|r|dstt|r||q|j|qdS)z;Add `urls` to the list that will be prescanned for searchesNfile:)rrr+rrrappend)rurlsr:r#r#r$add_find_linkss   zPackageIndex.add_find_linkscCs"|jr tt|j|jd|_dS)z7Scan urls scheduled for prescanning (e.g. --find-links)N)rrrqrrr#r#r$rs zPackageIndex.prescancCs<||jr |jd}}n|jd}}|||j|dS)Nz#Couldn't retrieve index page for %rz3Couldn't find index page for %r (maybe misspelled?))rrrrr)rrmethrr#r#r$rs   zPackageIndex.not_found_in_indexcCsvt|ts1t|}|r%|||}t|\}}|dr#||||}|Stj |r-|St |}t | ||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. rrLN) rrr _download_urlrBr* gen_setuprXr>rr%rfetch_distribution)rr!tmpdirr<foundr-rAr#r#r$r2$s     zPackageIndex.downloadc sd|id}d fdd }|r$|||}|s/|dur/|||}|dur@jdur<||}|durO|sO|||}|dur`drZdp[d|dSd||j|jd S) a|Obtain a distribution suitable for fulfilling `requirement` `requirement` must be a ``pkg_resources.Requirement`` instance. If necessary, or if the `force_scan` flag is set, the requirement is searched for in the (online) package index as well as the locally installed packages. If a distribution matching `requirement` is found, the returned distribution's ``location`` is the value you would have gotten from calling the ``download()`` method with the matching distribution's URL or filename. If no matching distribution is found, ``None`` is returned. If the `source` flag is set, only source distributions and source checkout links will be considered. Unless the `develop_ok` flag is set, development and system eggs (i.e., those using the ``.egg-info`` format) will be ignored. zSearching for %sNcs|dur}||jD];}|jtkr#s#|vr"d|d|<q ||vo.|jtkp. }|rF|j}||_tj |jrF|Sq dS)Nz&Skipping development or system egg: %sr5) rrCrrrr2rLdownload_locationrXr>r)reqenvrItestloc develop_okrskippedsourcerr#r$rw^s(z-PackageIndex.fetch_distribution..findz:No local packages or working download links found for %s%sza source distribution of rzBest match: %s)rLrd)rrrrrcloner) rrr force_scanr r local_indexrIrwr#rr$rFs2         zPackageIndex.fetch_distributioncCs"|||||}|dur|jSdS)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)rrL)rrrr"r rIr#r#r$fetchszPackageIndex.fetchc Cs t|}|rddt||ddDpg}t|dkrxtj|}tj||krEtj ||}ddl m }|||sEt |||}ttj |dd} | d|dj|djtj|dfWd|S1sqwY|S|rtd ||ftd ) NcSsg|]}|jr|qSr#)rN)r\dr#r#r$ s z*PackageIndex.gen_setup..r5r)samefilezsetup.pywzIfrom setuptools import setup setup(name=%r, version=%r, py_modules=[%r]) zCan't unambiguously interpret project/version identifier %r; any dashes in the name or version should be escaped using underscores. %rzpCan't process plain .py files without an '#egg=name-version' suffix to enable automatic setup script generation.)rErFrrGrRrXr>rSdirnamercsetuptools.command.easy_installr'shutilcopy2rwriterMrNsplitextr) rrYrArrFrrSdstr'rr#r#r$rsF          zPackageIndex.gen_setupi c Cs2|d|d}zt|}||}t|tjjr%td||j |j f|}d}|j }d}d|vrI| d} t tt| }||||||t|d1} ||} | ro|| | | |d 7}||||||nnqP|||| Wdn1swY|W|r|SS|r|ww) NzDownloading %szCan't download %s: %s %srr1zcontent-lengthzContent-LengthwbTr5)rrrrrr6rrrrr dl_blocksizeget_allmaxrqint reporthookrrrr-r r) rr:rYfpr rblocknumbssizesizesr rr#r#r$ _download_tosF            zPackageIndex._download_tocCsdSrdr#)rr:rYr7blksizer9r#r#r$r5zPackageIndex.reporthookc Cs|dr t|Szt||jWSttjjfyD}z$ddd|j D}|r0| ||n t d||f|WYd}~dSd}~wt j jyY}z|WYd}~Sd}~wt j jy}z|rl| ||jn t d||jf|WYd}~dSd}~wtjjy}z|r| ||jn t d||jf|WYd}~dSd}~wtjjtj fy}z|r| ||n t d||f|WYd}~dSd}~ww)Nr cSsg|]}t|qSr#)rr)r\argr#r#r$r&sz)PackageIndex.open_url..z%s %szDownload error for %s: %sz;%s returned a bad status line. The server might be down, %s)r+ local_openopen_with_authrr httpclient InvalidURLrcrerrr6rrURLErrorreason BadStatusLineline HTTPExceptionsocket)rr:warningvrr#r#r$rs^ zPackageIndex.open_urlcCsvt|\}}|rd|vr|dddd}d|vs nd}|dr(|dd}tj||}|||p:|||S)Nz...\___downloaded__rJr()rBreplacer*rXr>rc _download_vcs_download_other)rr:rr,rArYr#r#r$rs   zPackageIndex._download_urlcCsLtj|j}|d\}}}tddgdgt|}tt|h|@dS)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) r6rurlsplitr< partitionrpboolnextiter)r:r<preseppostallowedr#r#r$ _resolve_vcs&s zPackageIndex._resolve_vcsc Cs||}|s dS|dkr|||S|d\}}}||\}}|d|d|d|t|dd||gt|d|d d|g|d |d dd |d gd}|dura|d|t|||S)NrUr4zDoing z clone from z to r!z--quietz-Ccheckoutz--cwdupz-r-q)rVrWz Checking out )ra _download_svnrY_vcs_split_rev_from_urlr subprocess check_calldict)rr: spec_filenamevcsrYrOrev co_commandsr#r#r$rR9s"  zPackageIndex._download_vcscCsDtj|j}|dkrtjtj|jS||d| ||S)NrT) r6rrXr<r url2pathnamer7r>r_attempt_download)rr:rYr<r#r#r$rSPs   zPackageIndex._download_othercCs||ddS)NT)rrr#r#r$rXrzPackageIndex.scan_urlcCs2|||}d|ddvr||||S|S)Nrrr)r;rr)_download_html)rr:rYrr#r#r$ro[s zPackageIndex._attempt_downloadcCsjt|}|D]}|r%td|r#|t||||Snq|t|td|)Nz ([^- ]+ - )?Revision \d+:zUnexpected HTML page found at ) r���rs���r[���rx���r���rX���r ��re��r���)r���r:���r���rY���r���rH��r#���r#���r$���rp��b��s���    zPackageIndex._download_htmlc�����������������C���s��t�dt�|ddd�}g�}|�drwd|v�rwtj|\}}}}}} |sw|drwd|d d��v�rw|d d��dd\}}t |\} } | rwd | v�r`| d d\} } | d | d | g�n| d | g�| }|||||| f}tj |}|� d ||�g�d|�||g�}t |�|S�)Nz"SVN download support is deprecatedr4���r5���r���zsvn:@z//r0���r_���:z --usernamez --passwordz'Doing subversion checkout from %s to %s)rU��rb��rd��)warningsr��� UserWarningr9���r)���r+���r6���r���r7��� _splituserextend urlunparser���rg��rh��)r���r:���rY���credsr<���netlocr>���r]���qr���authhostuserpwr;���cmdr#���r#���r$���re��q��s(���    zPackageIndex._download_svnc����������� ������C���st���t�j|�}|jddd�}|jd\}}}|d\}}}|r&||fn|df\}} |j||dd �} | | 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) rT��r5���r1���r4���rq��Nr���)r<���r>���rA���) r6���r���rX��r<���r9���r>���rY�� rpartition_replacegeturl) r:���r;��� clean_schemeno_fragment_pathrO��r]��r^��r_�� clean_pathrl��resolvedr#���r#���r$���rf����s��� z$PackageIndex._vcs_split_rev_from_urlc�����������������G������t�j|g|R���d�S�rd���)r���r���r��r#���r#���r$���r��������zPackageIndex.debugc�����������������G���r��rd���)r���r���r��r#���r#���r$���r�����r��zPackageIndex.infoc�����������������G���r��rd���)r���r���r��r#���r#���r$���r�����r��zPackageIndex.warn)r���r���NT)Frd���)FFFN)FF)+r���r���r���r���r���r���r���r���r���r���r���r���r���r���r���r��r��r ��r��r��r��r2���r��r$��r��r1��r;��r5��r���r�� staticmethodra��rR��rS��r���ro��rp��re��rf��r���r���r��� __classcell__r#���r#���r���r$���r�����sZ���� 5       # L )$ #  r���z!&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?c�����������������C���s���|��d}t|S�)Nr���)rG���r���unescape)rF���whatr#���r#���r$��� decode_entity��s���  r��c�����������������C���s ���t�t|�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��)textr#���r#���r$���rv�����s��� rv���c��������������������s����fdd}|S�)Nc��������������������s����fdd}|S�)Nc��������������� ������s:���t��}t��z �|�i�|W�t�|�S�t�|�w�rd���)rJ��getdefaulttimeoutsetdefaulttimeout)re���rf��� old_timeout)rh���timeoutr#���r$���_socket_timeout��s ��� z@socket_timeout.<locals>._socket_timeout.<locals>._socket_timeoutr#���)rh���r��r��rg���r$���r����s���z'socket_timeout.<locals>._socket_timeoutr#���)r��r��r#���r��r$���socket_timeout��s���  r��c�����������������C���s2���t�j|�}|�}t|}|�}|ddS�)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���)r6���r���r8���encodebase64 b64encoder���rQ��)r{��auth_s auth_bytes encoded_bytesencodedr#���r#���r$��� _encode_auth��s ���   r��c�������������������@���r���) Credentialz: A username/password pair. Use like a namedtuple. c�����������������C���s���||�_�||�_d�S�rd���usernamepassword)r���r��r��r#���r#���r$���r�����s��� zCredential.__init__c�����������������c���s����|�j�V��|�jV��d�S�rd���r��r���r#���r#���r$���__iter__��s��� zCredential.__iter__c�����������������C���s ���dt�|��S�)Nz%(username)s:%(password)s)varsr���r#���r#���r$���__str__��s��� zCredential.__str__N)r���r���r���r���r���r��r��r#���r#���r#���r$���r����s ���� r��c�������������������@���s0���e�Zd�Zdd�Zedd�Zdd�Zdd�Zd S�) PyPIConfigc�����������������C���sR���t�g�dd}tj|�|�tjtjdd}tj |r'|� |�dS�dS�)z% Load from ~/.pypirc )r��r�� repositoryr���~z.pypircN) ri��fromkeys configparserRawConfigParserr���rX���r>���rc��� expanduserr���r���)r���defaultsrcr#���r#���r$���r�����s ��� zPyPIConfig.__init__c��������������������s&����fdd���D�}tt�j|S�)Nc��������������������s ���g�|�] }��|d��r|qS�)r��)r���rs���)r\���sectionr���r#���r$���r&�� ��s ����z2PyPIConfig.creds_by_repository.<locals>.<listcomp>)sectionsri��rq���_get_repo_cred)r���sections_with_repositoriesr#���r���r$���creds_by_repository ��s��� zPyPIConfig.creds_by_repositoryc�����������������C���s6���|��|d�}|t|��|d�|��|d�fS�)Nr��r��r��)r���rs���r��)r���r��repor#���r#���r$���r����s ���zPyPIConfig._get_repo_credc�����������������C���s*���|�j��D�] \}}||r|��S�qdS�)z If the URL indicated appears to be a repository defined in this config, return the credential for that repository. N)r��itemsr+���)r���r:���r��credr#���r#���r$���find_credential��s ��� zPyPIConfig.find_credentialN)r���r���r���r���propertyr��r��r��r#���r#���r#���r$���r����s ����  r��c�����������������C���s:��t�j|�}|\}}}}}}|drtjd|dv�r$t|\} } nd} | sBt� |�} | rBt | } | j |�f} t j dg| R���| redt| �} || ||||f} t�j| }t�j|}|d| �nt�j|�}|dt�||}| rt�j|j\}}}}}}||kr|| kr||||||f} t�j| |_|S�) z4Open a urllib2 request, handling HTTP authenticationrr��znonnumeric port: '')rB��httpsNz*Authenticating as %s for %s (from .pypirc)zBasic Authorizationz User-Agent)r6���r���r7���r*���rB��rC��rD��ru��r��r��rr���r��r���r���r��rw��r���Request add_header user_agentr:���)r:���r���parsedr<���ry��r>���paramsr@���r���r{��addressr��r���r;���r���r���r6��s2h2path2param2query2frag2r#���r#���r$���rA��$��s8���          rA��c�����������������C���s$���|��d\}}}�|r||�fS�d|�fS�)zNsplituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.rq��N)r��)r|��r}��delimr#���r#���r$���ru��S��s���ru��c�����������������C���s���|�S�rd���r#���)r:���r#���r#���r$��� fix_sf_url^��r=��r��c�������������� ���C���s*��t�j|�\}}}}}}t�j|}tj|rt�j|�S�| dr}tj |r}g�}t |D�];} tj || } | dkrXt | d } | �} W�d���n1�sQw���Y���n tj | rb| d7�} |dj| d�q0d} | j|�d |d } d \}}nd \}}} d d i}t| }t�j|�||||S�)z7Read a local path, with special support for directoriesr0���z index.htmlrNz<a href="{name}">{name}</a>)r,���zB<html><head><title>{url}{files}r)r:files)OK)rzPath not foundz Not foundrz text/html)r6rr7rrnrXr>isfilerr*rrrcrrrformatioStringIOrr)r:r<r=r>paramr@rrYrrfilepathr6bodyrstatusmessager body_streamr#r#r$r@bs0         r@rd)r)[rsysrgrXr[rr+rJrrrrsrr http.clientrB urllib.parser6urllib.request urllib.error functoolsrr pkg_resourcesrrrrrr r r r r rrrr distutilsrdistutils.errorsrfnmatchrsetuptools.wheelr setuptools.extern.more_itertoolsrrrEIrtrrFrr9rQ__all___SOCKET_TIMEOUT_tmplr version_inforr%rrBrrDrZrrjrmr~rrrrrrrvrrrrrrrrArurr@r#r#r#r$s @          ! #  !  &/