3 ”Re„Ëã@sDddlZddlmZddlZddlZddlZddlZddlZy ddlZWne k rdddl ZYnXddl Z ddl m Z ddlmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZddlm Z m!Z!m"Z"ddl#m$Z$m%Z%ddl&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/dd l0m1Z1m2Z2dd l3m4Z4m5Z5ej6e7ƒZ8ej9d ƒZ:ej9d ej;ƒZd-dd„Z?Gdd„deƒZ@Gdd„deAƒZBGdd„deBƒZCGdd„deBƒZDGdd„deAƒZEGdd„deBƒZFGdd„deBƒZGGdd „d eBƒZHGd!d"„d"eBƒZIGd#d$„d$eBƒZJeJeHƒeFd%d&d'�d(d)�ZKeKjLZLej9d*ƒZMGd+d,„d,eAƒZNdS).éN)ÚBytesIOé)ÚDistlibException)ÚurljoinÚurlparseÚ urlunparseÚ url2pathnameÚ pathname2urlÚqueueÚquoteÚunescapeÚ string_typesÚ build_openerÚHTTPRedirectHandlerÚ text_typeÚRequestÚ HTTPErrorÚURLError)Ú DistributionÚDistributionPathÚ make_dist)ÚMetadataÚMetadataInvalidError) Úcached_propertyÚparse_credentialsÚ ensure_slashÚsplit_filenameÚget_project_dataÚparse_requirementÚparse_name_and_versionÚ ServerProxyÚnormalize_name)Ú get_schemeÚUnsupportedVersionError)ÚWheelÚ is_compatiblez^(\w+)=([a-f0-9]+)z;\s*charset\s*=\s*(.*)\s*$ztext/html|application/x(ht)?mlzhttps://pypi.org/pypic Cs2|dkr t}t|dd�}z|jƒS|dƒƒXdS)z• Return all distribution names known by an index. :param url: The URL of the index. :return: A list of all known distribution names. Ng@)ÚtimeoutÚclose)Ú DEFAULT_INDEXr Ú list_packages)ÚurlÚclient©r,ú‹/builddir/build/BUILDROOT/alt-python36-pip-20.2.4-5.el8.x86_64/opt/alt/python36/lib/python3.6/site-packages/pip/_vendor/distlib/locators.pyÚget_all_distribution_names)s  r.c@s$eZdZdZdd„ZeZZZdS)ÚRedirectHandlerzE A class to work around a bug in some Python 3.2.x releases. c Cs„d}xdD]}||kr ||}Pq W|dkr0dSt|ƒ}|jdkrpt|jƒ|ƒ}t|dƒrh|j||ƒn|||<tj||||||ƒS)NÚlocationÚuriÚÚreplace_header)r0r1)rÚschemerÚ get_full_urlÚhasattrr3ÚBaseRedirectHandlerÚhttp_error_302) ÚselfÚreqÚfpÚcodeÚmsgÚheadersÚnewurlÚkeyÚurlpartsr,r,r-r8@s   zRedirectHandler.http_error_302N)Ú__name__Ú __module__Ú __qualname__Ú__doc__r8Úhttp_error_301Úhttp_error_303Úhttp_error_307r,r,r,r-r/7sr/c@s¶eZdZdZd/Zd0Zd1Zd Zed2Zd3dd„Z dd„Z dd„Z dd„Z dd„Z dd„Zee eƒZdd„Zdd„Zdd„Zd d!„Zd"d#„Zd$d%„Zd&d'„Zd(d)„Zd*d+„Zd4d-d.„Zd S)5ÚLocatorzG A base class for locators - things that locate distributions. ú.tar.gzú.tar.bz2ú.tarú.zipú.tgzú.tbzú.eggú.exeú.whlú.pdfNÚdefaultcCs,i|_||_ttƒƒ|_d|_tjƒ|_dS)a^ Initialise an instance. :param scheme: Because locators look for most recent versions, they need to know the version scheme to use. This specifies the current PEP-recommended scheme - use ``'legacy'`` if you need to support existing distributions on PyPI. N) Ú_cacher4rr/ÚopenerÚmatcherr ÚQueueÚerrors)r9r4r,r,r-Ú__init__fs  zLocator.__init__c CsXg}xN|jjƒsRy|jjdƒ}|j|ƒWn|jjk rDwYnX|jjƒqW|S)z8 Return any errors which have occurred. F)rYÚemptyÚgetÚappendÚEmptyÚ task_done)r9ÚresultÚer,r,r-Ú get_errorsys  zLocator.get_errorscCs |jƒdS)z> Clear any errors which may have been logged. N)rb)r9r,r,r-Ú clear_errors‡szLocator.clear_errorscCs|jjƒdS)N)rUÚclear)r9r,r,r-Ú clear_cacheŽszLocator.clear_cachecCs|jS)N)Ú_scheme)r9r,r,r-Ú _get_scheme‘szLocator._get_schemecCs ||_dS)N)rf)r9Úvaluer,r,r-Ú _set_scheme”szLocator._set_schemecCs tdƒ‚dS)a= For a given project, get a dictionary mapping available versions to Distribution instances. This should be implemented in subclasses. If called from a locate() request, self.matcher will be set to a matcher for the requirement to satisfy, otherwise it will be None. z Please implement in the subclassN)ÚNotImplementedError)r9Únamer,r,r-Ú _get_project™s zLocator._get_projectcCs tdƒ‚dS)zJ Return all the distribution names known to this locator. z Please implement in the subclassN)rj)r9r,r,r-Úget_distribution_names¥szLocator.get_distribution_namescCsL|jdkr|j|ƒ}n2||jkr,|j|}n|jƒ|j|ƒ}||j|<|S)zÖ For a given project, get a dictionary mapping available versions to Distribution instances. This calls _get_project to do all the work, and just implements a caching layer on top. N)rUrlrc)r9rkr`r,r,r-Ú get_project«s      zLocator.get_projectcCs^t|ƒ}tj|jƒ}d}|jdƒ}|j|jƒ}|rBtt|ƒ|jƒ}|j dkd|j k||||fS)zu Give an url a score which can be used to choose preferred URLs for a given project release. Tz.whlÚhttpszpypi.org) rÚ posixpathÚbasenameÚpathÚendswithÚdownloadable_extensionsr%r$Ú wheel_tagsr4Únetloc)r9r*ÚtrqÚ compatibleÚis_wheelZis_downloadabler,r,r-Ú score_url¼s   zLocator.score_urlcCsR|}|rN|j|ƒ}|j|ƒ}||kr(|}||kr@tjd||ƒntjd||ƒ|S)a{ Choose one of two URLs where both are candidates for distribution archives for the same version of a distribution (for example, .tar.gz vs. zip). The current implementation favours https:// URLs over http://, archives from PyPI over those from other locations, wheel compatibility (if a wheel) and then the archive name. zNot replacing %r with %rzReplacing %r with %r)rzÚloggerÚdebug)r9Úurl1Úurl2r`Ús1Ús2r,r,r-Ú prefer_urlËs   zLocator.prefer_urlcCs t||ƒS)zZ Attempt to split a filename in project name, version and Python version. )r)r9ÚfilenameÚ project_namer,r,r-rászLocator.split_filenamecCs dd„}d}t|ƒ\}}}}} } | jƒjdƒry~t |ƒ}t ||j ƒs°tjd |ƒnX|dkr¾d }n ||j |ƒ}|�r|j |j |jt||||| d fƒd jd d„|jDƒƒdœ}Wn0tk �r:}ztjd|ƒWYdd}~XnXnÆ|j|jƒ�sZtjd|ƒnªtj|ƒ}}xš|jD]�}|j|ƒ�rp|dt|ƒ …}|j||ƒ}|�s²tjd|ƒnJ|\}}}| �sÐ|||ƒ�rü|||t||||| d fƒdœ}|�rü||d<P�qpW|�r| �r| |d| <|S)a See if a URL is a candidate for a download URL for a project (the URL has typically been scraped from an HTML page). If it is, a dictionary is returned with keys "name", "version", "filename" and "url"; otherwise, None is returned. cSst|ƒt|ƒkS)N)r!)Zname1Zname2r,r,r-Ú same_projectïsz:Locator.convert_url_to_download_info..same_projectNzegg=z %s: version hint in fragment: %rrú/z.whlzWheel not compatible: %sTr2z, cSs"g|]}djt|dd…ƒƒ‘qS)Ú.éN)ÚjoinÚlist)Ú.0Úvr,r,r-ú sz8Locator.convert_url_to_download_info..)rkÚversionr‚r*zpython-versionzinvalid path for wheel: %szNot downloadable: %sz No match for project/version: %s)rkr�r‚r*zpython-versionz %s_digest)NNéÿÿÿÿrŽ)rÚlowerÚ startswithr{r|Ú HASHER_HASHÚmatchÚgroupsrsr$r%rurkr�r‚rrˆÚpyverÚ ExceptionÚwarningrtrprqÚlenr)r9r*rƒr„r`r4rvrrÚparamsÚqueryÚfragÚmÚalgoÚdigestZorigpathÚwheelÚincluderar‚Úextrwrkr�r”r,r,r-Úconvert_url_to_download_infoçsj             z$Locator.convert_url_to_download_infocCsld}d|kr8|d}x"dD]}||kr|||f}PqW|shx*dD]"}d|}||krB|||f}PqBW|S)zò Get a digest from a dictionary by looking at a "digests" dictionary or keys of the form 'algo_digest'. Returns a 2-tuple (algo, digest) if found, else None. Currently looks only for SHA256, then MD5. NÚdigestsÚsha256Úmd5z %s_digest)r£r¤)r£r¤r,)r9Úinfor`r¢rœr@r,r,r-Ú _get_digest1s    zLocator._get_digestc Cs®|jdƒ}|jdƒ}||kr,||}|j}nt|||jd�}|j}|j|ƒ|_}|d}||d|<|j|dkrœ|j|j|ƒ|_|dj|t ƒƒj |ƒ||_ |||<dS)zñ Update a result dictionary (the final result from _get_project) with a dictionary for a specific version, which typically holds information gleaned from a filename or URL for an archive for the distribution. rkr�)r4r*r¢ÚurlsN) ÚpopÚmetadatarr4r¦r�Ú source_urlr�Ú setdefaultÚsetÚaddÚlocator) r9r`r¥rkr�ÚdistÚmdr�r*r,r,r-Ú_update_version_dataHs   zLocator._update_version_dataFc Cs®d}t|ƒ}|dkr td|ƒ‚t|jƒ}|j|jƒ|_}tjd|t|ƒj ƒ|j |j ƒ}t |ƒdk�r8g}|j } x„|D]|} | d krˆqzyJ|j| ƒs¤tjd|| ƒn,|s´| | ƒj rÀ|j| ƒntjd| |j ƒWqztk rôtjd || ƒYqzXqzWt |ƒd k�rt||jd �}|�r8tjd |ƒ|d} || }|�r¤|j�rN|j|_|jdiƒj| tƒƒ|_i} |jdiƒ} x&|jD]}|| k�r~| || |<�q~W| |_d|_|S)a Find the most recent distribution which matches the given requirement. :param requirement: A requirement of the form 'foo (1.0)' or perhaps 'foo (>= 1.0, < 2.0, != 1.3)' :param prereleases: If ``True``, allow pre-release versions to be located. Otherwise, pre-release versions are not returned. :return: A :class:`Distribution` instance, or ``None`` if no such distribution could be located. NzNot a valid requirement: %rzmatcher: %s (%s)r‡r§r¢z%s did not match %rz%skipping pre-release version %s of %szerror matching %s with %rr)r@zsorted list: %s)r§r¢rŽ)rrr"r4rWÚ requirementr{r|ÚtyperBrnrkr—Z version_classr’Ú is_prereleaser]r•r–Úsortedr@Úextrasr\r¬Ú download_urlsr¢)r9r²Ú prereleasesr`Úrr4rWÚversionsÚslistZvclsÚkr�ÚdÚsdr*r,r,r-Úlocate_sT            zLocator.locate)rJrKrLrMrNrO)rPrQrR)rS)rR)rT)F)rBrCrDrEÚsource_extensionsÚbinary_extensionsÚexcluded_extensionsrurtrZrbrcrergriÚpropertyr4rlrmrnrzr�rr¡r¦r±r¿r,r,r,r-rIVs.   JrIcs0eZdZdZ‡fdd„Zdd„Zdd„Z‡ZS)ÚPyPIRPCLocatorz‘ This locator uses XML-RPC to locate distributions. It therefore cannot be used with simple mirrors (that only mirror file content). c s*tt|ƒjf|Ž||_t|dd�|_dS)z— Initialise an instance. :param url: The URL to use for XML-RPC. :param kwargs: Passed to the superclass constructor. g@)r&N)ÚsuperrÄrZÚbase_urlr r+)r9r*Úkwargs)Ú __class__r,r-rZ szPyPIRPCLocator.__init__cCst|jjƒƒS)zJ Return all the distribution names known to this locator. )r¬r+r))r9r,r,r-rm«sz%PyPIRPCLocator.get_distribution_namesc Csiidœ}|jj|dƒ}xê|D]â}|jj||ƒ}|jj||ƒ}t|jd�}|d|_|d|_|jdƒ|_ |jdgƒ|_ |jdƒ|_ t |ƒ}|r|d } | d |_ |j| ƒ|_||_|||<xB|D]:} | d } |j| ƒ} |d j|tƒƒj| ƒ| |d | <qÂWqW|S) N)r§r¢T)r4rkr�ÚlicenseÚkeywordsÚsummaryrr*r§r¢)r+Zpackage_releasesZ release_urlsZ release_datarr4rkr�r\rÉrÊrËrrªr¦r�r®r«r¬r­) r9rkr`rºr‹r§Údatar©r¯r¥r*r�r,r,r-rl±s0           zPyPIRPCLocator._get_project)rBrCrDrErZrmrlÚ __classcell__r,r,)rÈr-rÄ›s rÄcs0eZdZdZ‡fdd„Zdd„Zdd„Z‡ZS)ÚPyPIJSONLocatorzw This locator uses PyPI's JSON interface. It's very limited in functionality and probably not worth using. c s tt|ƒjf|Žt|ƒ|_dS)N)rÅrÎrZrrÆ)r9r*rÇ)rÈr,r-rZÐszPyPIJSONLocator.__init__cCs tdƒ‚dS)zJ Return all the distribution names known to this locator. zNot available from this locatorN)rj)r9r,r,r-rmÔsz&PyPIJSONLocator.get_distribution_namescCsiidœ}t|jdt|ƒƒ}�y°|jj|ƒ}|jƒjƒ}tj|ƒ}t |j d�}|d}|d|_ |d|_ |j dƒ|_|j dgƒ|_|j d ƒ|_t|ƒ}||_|d } |||j <x`|d D]T} | d }|jj|ƒ|j| ƒ|j|<|d j|j tƒƒj|ƒ|j| ƒ|d |<q¼Wx¸|d jƒD]¨\} } | |j k�r:�q"t |j d�} |j | _ | | _ t| ƒ}||_||| <x\| D]T} | d }|jj|ƒ|j| ƒ|j|<|d j| tƒƒj|ƒ|j| ƒ|d |<�qpW�q"WWn@tk �r}z"|jjt|ƒƒtjd|ƒWYdd}~XnX|S)N)r§r¢z%s/json)r4r¥rkr�rÉrÊrËr§r*r¢ZreleaseszJSON fetch failed: %s) rrÆr rVÚopenÚreadÚdecodeÚjsonÚloadsrr4rkr�r\rÉrÊrËrr®r·r­r¦r¢r«r¬Úitemsr•rYÚputrr{Ú exception)r9rkr`r*ÚresprÌr½r°r¯r§r¥r�ÚinfosZomdÚodistrar,r,r-rlÚsT               " zPyPIJSONLocator._get_project)rBrCrDrErZrmrlrÍr,r,)rÈr-rÎËs rÎc@s`eZdZdZejdejejBejBƒZ ejdejejBƒZ dd„Z ejdejƒZ e dd„ƒZd S) ÚPagez4 This class represents a scraped HTML page. zÝ (rel\s*=\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\s ]*))\s+)? href\s*=\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\s ]*)) (\s+rel\s*=\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\s ]*)))? z!]+)cCs4||_||_|_|jj|jƒ}|r0|jdƒ|_dS)zk Initialise an instance with the Unicode page contents and the URL they came from. rN)rÌrÆr*Ú_baseÚsearchÚgroup)r9rÌr*r›r,r,r-rZ s  z Page.__init__z[^a-z0-9$&+,/:;=?@.#%_\\|-]cCsÂdd„}tƒ}xœ|jj|jƒD]Š}|jdƒ}|dpZ|dpZ|dpZ|dpZ|dpZ|d }|d pr|d pr|d }t|j|ƒ}t|ƒ}|jj d d„|ƒ}|j ||fƒqWt |dd„dd�}|S)zâ Return the URLs of all the links on a page together with information about their "rel" attribute, for determining which ones to treat as downloads and which ones to queue for further scraping. cSs,t|ƒ\}}}}}}t||t|ƒ|||fƒS)zTidy up an URL.)rrr )r*r4rvrrr˜r™ršr,r,r-Úclean4s zPage.links..cleanr2Zrel1Zrel2Zrel3Zrel4Zrel5Zrel6r}r~Zurl3cSsdt|jdƒƒS)Nz%%%2xr)ÚordrÝ)r›r,r,r-ÚBszPage.links..cSs|dS)Nrr,)rwr,r,r-ràFsT)r@Úreverse) r¬Ú_hrefÚfinditerrÌÚ groupdictrrÆr Ú _clean_reÚsubr­rµ)r9rÞr`r’r½Úrelr*r,r,r-Úlinks-s  z Page.linksN)rBrCrDrEÚreÚcompileÚIÚSÚXrârÛrZrårrèr,r,r,r-rÚs rÚcs˜eZdZdZejdd„dd„dœZd‡fdd „ Zd d „Zd d „Z dd„Z e j de j ƒZdd„Zdd„Zdd„Zdd„Zdd„Ze j dƒZdd„Z‡ZS)ÚSimpleScrapingLocatorzã A locator which scrapes HTML pages to locate downloads for a distribution. This runs multiple threads to do the I/O; performance is at least as good as pip's PackageFinder, which works in an analogous fashion. cCstjttƒd�jƒS)N)Úfileobj)ÚgzipÚGzipFilerr½rÐ)Úbr,r,r-ràTszSimpleScrapingLocator.cCs|S)Nr,)ròr,r,r-ràUs)ÚdeflaterðÚnoneNé c sltt|ƒjf|Žt|ƒ|_||_i|_tƒ|_t j ƒ|_ tƒ|_ d|_ ||_tjƒ|_tjƒ|_d|_dS)a¤ Initialise an instance. :param url: The root URL to use for scraping. :param timeout: The timeout, in seconds, to be applied to requests. This defaults to ``None`` (no timeout specified). :param num_workers: The number of worker threads you want to do I/O, This defaults to 10. :param kwargs: Passed to the superclass. FN)rÅrîrZrrÆr&Ú _page_cacher¬Ú_seenr rXÚ _to_fetchÚ _bad_hostsÚskip_externalsÚ num_workersÚ threadingÚRLockÚ_lockÚ_gplockÚplatform_check)r9r*r&rûrÇ)rÈr,r-rZXs     zSimpleScrapingLocator.__init__cCsJg|_x>t|jƒD]0}tj|jd�}|jdƒ|jƒ|jj|ƒqWdS)z¾ Threads are created only when get_project is called, and terminate before it returns. They are there primarily to parallelise I/O (i.e. fetching web pages). )ÚtargetTN) Ú_threadsÚrangerûrüÚThreadÚ_fetchÚ setDaemonÚstartr])r9Úirwr,r,r-Ú_prepare_threadsss  z&SimpleScrapingLocator._prepare_threadscCs>x|jD]}|jjdƒqWx|jD] }|jƒq$Wg|_dS)zu Tell all the threads to terminate (by sending a sentinel value) and wait for them to do so. N)rrørÕrˆ)r9rwr,r,r-Ú _wait_threads€s    z#SimpleScrapingLocator._wait_threadscCs’iidœ}|j�x||_||_t|jdt|ƒƒ}|jjƒ|jjƒ|j ƒz&t j d|ƒ|j j |ƒ|j jƒWd|jƒX|`WdQRX|S)N)r§r¢z%s/z Queueing %s)rÿr`rƒrrÆr r÷rdrör r{r|rørÕrˆr )r9rkr`r*r,r,r-rl�s      z"SimpleScrapingLocator._get_projectz<\b(linux_(i\d86|x86_64|arm\w+)|win(32|_amd64)|macosx_?\d+)\bcCs |jj|ƒS)zD Does an URL refer to a platform-specific download? )Úplatform_dependentrÜ)r9r*r,r,r-Ú_is_platform_dependent¢sz,SimpleScrapingLocator._is_platform_dependentc CsZ|jr|j|ƒrd}n|j||jƒ}tjd||ƒ|rV|j�|j|j|ƒWdQRX|S)a% See if an URL is a suitable download for a project. If it is, register information in the result dictionary (for _get_project) about the specific version it's for. Note that the return value isn't actually used other than as a boolean value. Nzprocess_download: %s -> %s) rr r¡rƒr{r|rþr±r`)r9r*r¥r,r,r-Ú_process_download¨s z'SimpleScrapingLocator._process_downloadc CsÆt|ƒ\}}}}}}|j|j|j|jƒr2d}n~|jrL|j|jƒ rLd}nd|j|jƒs^d}nR|d krld}nD|dkrzd}n6|j|ƒrŠd}n&|j ddƒd } | j ƒd kr¬d}nd }t j d ||||ƒ|S)z‘ Determine whether a link URL from a referring page and with a particular "rel" attribute should be queued for scraping. FÚhomepageÚdownloadÚhttproÚftpú:rrÚ localhostTz#should_queue: %s (%s) from %s -> %s)rr)rror) rrsrÀrÁrÂrúr�rÆr Úsplitr�r{r|) r9ÚlinkZreferrerrçr4rvrrÚ_r`Úhostr,r,r-Ú _should_queue¼s*     z#SimpleScrapingLocator._should_queuecCsôxî|jjƒ}zÌy”|r |j|ƒ}|dkr(wxv|jD]l\}}||jkr0yD|jj|ƒ|j|ƒ r„|j|||ƒr„tj d||ƒ|jj |ƒWq0t k ršYq0Xq0WWn2t k rÔ}z|j j t|ƒƒWYdd}~XnXWd|jjƒX|sPqWdS)z× Get a URL to fetch from the work queue, get the HTML page, examine its links for download candidates and candidates for further scraping. This is a handy method to run in a thread. NzQueueing %s from %s)rør\Úget_pagerèr÷r­r rr{r|rÕrr•rYrr_)r9r*Úpagerrçrar,r,r-rÙs,     & zSimpleScrapingLocator._fetchcCsXt|ƒ\}}}}}}|dkr:tjjt|ƒƒr:tt|ƒdƒ}||jkr`|j|}tj d||ƒ�nô|j ddƒd}d}||j kr�tj d||ƒ�nÄt |d d id �}�z¤yâtj d |ƒ|j j||jd �} tj d|ƒ| jƒ} | jddƒ} tj| ƒ�r„| jƒ} | jƒ} | jdƒ}|�r"|j|}|| ƒ} d}tj| ƒ}|�r@|jdƒ}y| j|ƒ} Wn tk �rn| jdƒ} YnXt| | ƒ}||j| <Wn¼tk �rÄ}z |jdk�r´tjd||ƒWYdd}~Xn€t k �r}z2tjd||ƒ|j!�|j j"|ƒWdQRXWYdd}~Xn2t#k �rB}ztjd||ƒWYdd}~XnXWd||j|<X|S)a Get the HTML for an URL, possibly from an in-memory cache. XXX TODO Note: this cache is never actually cleared. It's assumed that the data won't get stale over the lifetime of a locator instance (not necessarily true for the default_locator). Úfilez index.htmlzReturning %s from cache: %srrrNzSkipping %s due to bad host %szAccept-encodingÚidentity)r>z Fetching %s)r&z Fetched %sz Content-Typer2zContent-Encodingzutf-8zlatin-1i”zFetch failed: %s: %s)$rÚosrrÚisdirrrrrör{r|rrùrrVrÏr&r¥r\ÚHTML_CONTENT_TYPEr’ÚgeturlrÐÚdecodersÚCHARSETrÜrÝrÑÚ UnicodeErrorrÚrr<rÖrrþr­r•)r9r*r4rvrrrr`rr:r×r>Ú content_typeZ final_urlrÌÚencodingÚdecoderr›rar,r,r-rúsZ              &$ zSimpleScrapingLocator.get_pagez]*>([^<]+)rÇ)rÈr,r-rZ¯szDistPathLocator.__init__cCsP|jj|ƒ}|dkr iidœ}n,|j|d|jt|jgƒid|jtdgƒii}|S)N)r§r¢r§r¢)r>Úget_distributionr�r¬rª)r9rkr¯r`r,r,r-rl¹s  zDistPathLocator._get_project)rBrCrDrErZrlrÍr,r,)rÈr-r;ªs r;csReZdZdZ‡fdd„Z‡fdd„Zdd„Zeej j eƒZ dd „Z d d „Z ‡Z S) ÚAggregatingLocatorzI This class allows you to chain and/or merge a list of locators. cs*|jddƒ|_||_tt|ƒjf|ŽdS)aÏ Initialise an instance. :param locators: The list of locators to search. :param kwargs: Passed to the superclass constructor, except for: * merge - if False (the default), the first successful search from any of the locators is returned. If True, the results from all locators are merged (this can be slow). ÚmergeFN)r¨rAÚlocatorsrÅr@rZ)r9rBrÇ)rÈr,r-rZÊs zAggregatingLocator.__init__cs*tt|ƒjƒx|jD] }|jƒqWdS)N)rÅr@rerB)r9r®)rÈr,r-reÚs zAggregatingLocator.clear_cachecCs ||_x|jD] }||_qWdS)N)rfrBr4)r9rhr®r,r,r-rißs zAggregatingLocator._set_schemec Csôi}xê|jD]à}|j|ƒ}|r |jr®|jdiƒ}|jdiƒ}|j|ƒ|jdƒ}|r�|r�x6|jƒD]*\}} ||kr„||| O<qb| ||<qbW|jdƒ} |rì| rì| j|ƒq |jdkr¾d} n$d} x|D]}|jj|ƒrÈd} PqÈW| r |}Pq W|S)Nr§r¢TF)rBrnrAr\ÚupdaterÔrWr’) r9rkr`r®r½r3r¢Zdfr¼r‹ÚddÚfoundr,r,r-rlæs8           zAggregatingLocator._get_projectc Cs@tƒ}x4|jD]*}y||jƒO}Wqtk r6YqXqW|S)zJ Return all the distribution names known to this locator. )r¬rBrmrj)r9r`r®r,r,r-rms  z)AggregatingLocator.get_distribution_names)rBrCrDrErZrerirÃrIr4ÚfgetrlrmrÍr,r,)rÈr-r@Æs  ,r@zhttps://pypi.org/simple/g@)r&Úlegacy)r4z1(?P[\w-]+)\s*\(\s*(==\s*)?(?P[^)]+)\)$c@sLeZdZdZddd„Zdd„Zdd„Zd d „Zd d „Zd d„Z ddd„Z dS)ÚDependencyFinderz0 Locate dependencies for distributions. NcCs|pt|_t|jjƒ|_dS)zf Initialise an instance, using the specified locator to locate distributions. N)Údefault_locatorr®r"r4)r9r®r,r,r-rZ1s zDependencyFinder.__init__cCsvtjd|ƒ|j}||j|<||j||jf<xD|jD]:}t|ƒ\}}tjd|||ƒ|jj |t ƒƒj ||fƒq4WdS)z¨ Add a distribution to the finder. This will update internal information about who provides what. :param dist: The distribution to add. zadding distribution %szAdd to provided: %s, %s, %sN) r{r|r@Ú dists_by_nameÚdistsr�ÚprovidesrÚprovidedr«r¬r­)r9r¯rkÚpr�r,r,r-Úadd_distribution9s    z!DependencyFinder.add_distributioncCs|tjd|ƒ|j}|j|=|j||jf=xN|jD]D}t|ƒ\}}tjd|||ƒ|j|}|j ||fƒ|s0|j|=q0WdS)z° Remove a distribution from the finder. This will update internal information about who provides what. :param dist: The distribution to remove. zremoving distribution %sz Remove from provided: %s, %s, %sN) r{r|r@rJrKr�rLrrMÚremove)r9r¯rkrNr�Úsr,r,r-Úremove_distributionHs    z$DependencyFinder.remove_distributionc CsBy|jj|ƒ}Wn,tk r<|jƒd}|jj|ƒ}YnX|S)zÞ Get a version matcher for a requirement. :param reqt: The requirement :type reqt: str :return: A version matcher (an instance of :class:`distlib.version.Matcher`). r)r4rWr#r)r9ÚreqtrWrkr,r,r-Ú get_matcherZs  zDependencyFinder.get_matcherc Csv|j|ƒ}|j}tƒ}|j}||krrxL||D]@\}}y|j|ƒ}Wntk r\d}YnX|r.|j|ƒPq.W|S)zÓ Find the distributions which can fulfill a requirement. :param reqt: The requirement. :type reqt: str :return: A set of distribution which can fulfill the requirement. F)rTr@r¬rMr’r#r­) r9rSrWrkr`rMr�Úproviderr’r,r,r-Úfind_providersjs   zDependencyFinder.find_providersc Cs¦|j|}tƒ}x,|D]$}|j|ƒ}|j|jƒs|j|ƒqW|r^|jd||t|ƒfƒd}nD|j|ƒ|j|=x"|D]}|jj|tƒƒj|ƒqvW|j |ƒd}|S)aŠ Attempt to replace one provider with another. This is typically used when resolving dependencies from multiple sources, e.g. A requires (B >= 1.0) while C requires (B >= 1.1). For successful replacement, ``provider`` must meet all the requirements which ``other`` fulfills. :param provider: The provider we are trying to replace with. :param other: The provider we're trying to replace. :param problems: If False is returned, this will contain what problems prevented replacement. This is currently a tuple of the literal string 'cantreplace', ``provider``, ``other`` and the set of requirements that ``provider`` couldn't fulfill. :return: True if we can replace ``other`` with ``provider``, else False. Z cantreplaceFT) Úreqtsr¬rTr’r�r­Ú frozensetrRr«rO) r9rUÚotherÚproblemsZrlistÚ unmatchedrQrWr`r,r,r-Útry_to_replace‚s"         zDependencyFinder.try_to_replaceFcCs i|_i|_i|_i|_t|p gƒ}d|krH|jdƒ|tdddgƒO}t|tƒrh|}}tj d|ƒn4|j j ||d�}}|dkr�t d|ƒ‚tj d |ƒd |_ tƒ}t|gƒ}t|gƒ}�xú|�r¸|jƒ}|j} | |jkrê|j|ƒn"|j| } | |k�r |j|| |ƒ|j|jB} |j} tƒ} |�rh||k�rhx2dD]*}d|}||k�r:| t|d|ƒO} �q:W| | B| B}�x>|D�]4}|j|ƒ}|�sTtj d|ƒ|j j ||d�}|dk�rÐ| �rÐ|j j |d d�}|dk�rötj d|ƒ|jd|fƒn^|j|j}}||f|jk�r|j|ƒ|j|ƒ|| k�rT||k�rT|j|ƒtj d|jƒxZ|D]R}|j} | |jk�rˆ|jj|tƒƒj|ƒn"|j| } | |k�rZ|j|| |ƒ�qZW�q|WqÀWt|jjƒƒ}x.|D]&}||k|_|j�rÎtj d|jƒ�qÎWtj d|ƒ||fS)aŽ Find a distribution and all distributions it depends on. :param requirement: The requirement specifying the distribution to find, or a Distribution instance. :param meta_extras: A list of meta extras such as :test:, :build: and so on. :param prereleases: If ``True``, allow pre-release versions to be returned - otherwise, don't return prereleases unless they're all that's available. Return a set of :class:`Distribution` instances and a set of problems. The distributions returned should be such that they have the :attr:`required` attribute set to ``True`` if they were from the ``requirement`` passed to ``find()``, and they have the :attr:`build_time_dependency` attribute set to ``True`` unless they are post-installation dependencies of the ``requirement``. The problems should be a tuple consisting of the string ``'unsatisfied'`` and the requirement which couldn't be satisfied by any distribution known to the locator. z:*:z:test:z:build:z:dev:zpassed %s as requirement)r¸NzUnable to locate %rz located %sTÚtestÚbuildÚdevz:%s:z %s_requireszNo providers found for %rzCannot satisfy %rZ unsatisfiedzAdding %s to install_distsz#%s is a build-time dependency only.zfind done for %s)r]r^r_)rMrKrJrWr¬rPr<rr{r|r®r¿rÚ requestedr¨r@rOr\Z run_requiresZ meta_requiresZbuild_requiresÚgetattrrVr­r�Zname_and_versionr«ÚvaluesZbuild_time_dependency)r9r²Z meta_extrasr¸r¯rÙrZÚtodoZ install_distsrkrYZireqtsZsreqtsZereqtsr@raZ all_reqtsr¹Z providersrUÚnr‹rNrKr,r,r-ÚfindªsŒ                               zDependencyFinder.find)N)NF) rBrCrDrErZrOrRrTrVr\rer,r,r,r-rH,s (rH)N)OrðÚiorrÒÚloggingrrprérüÚ ImportErrorÚdummy_threadingr(r2rÚcompatrrrrr r r r r rrr7rrrrZdatabaserrrr©rrÚutilrrrrrrrr r!r�r"r#ržr$r%Ú getLoggerrBr{rêr‘rër"rr(r.r/ÚobjectrIrÄrÎrÚrîr*r5r;r@rIr¿ÚNAME_VERSION_RErHr,r,r,r-ÚsZ   D,    G0E:zA&[