U oÏ a„Ëã@sDddlZddlmZddlZddlZddlZddlZddlZz 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 l3m4Z4m5Z5e 6e7¡Z8e 9d ¡Z:e 9d 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)ZKeKjLZLe 9d*¡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/pypicCs6|dkr t}t|dd}z | ¡W¢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. Nç@©ÚtimeoutÚclose)Ú DEFAULT_INDEXr Ú list_packages)ÚurlÚclient©r.ú]C:\Users\vtejo\AppData\Local\Temp\pip-unpacked-wheel-6mt8ur68\pip\_vendor\distlib\locators.pyÚget_all_distribution_names)s   r0c@s$eZdZdZdd„ZeZZZdS)ÚRedirectHandlerzE A class to work around a bug in some Python 3.2.x releases. c Cs‚d}dD]}||kr||}q"q|dkr.dSt|ƒ}|jdkrnt| ¡|ƒ}t|dƒrf| ||¡n|||<t ||||||¡S)N)ÚlocationÚuriÚÚreplace_header)rÚschemerÚ get_full_urlÚhasattrr5ÚBaseRedirectHandlerÚhttp_error_302) ÚselfÚreqÚfpÚcodeÚmsgÚheadersÚnewurlÚkeyÚurlpartsr.r.r/r:@s   ÿzRedirectHandler.http_error_302N)Ú__name__Ú __module__Ú __qualname__Ú__doc__r:Úhttp_error_301Úhttp_error_303Úhttp_error_307r.r.r.r/r17sr1c@s¶eZdZdZdZdZdZdZedZd)dd „Z d d „Z d d „Z dd„Z dd„Z dd„Zee eƒZdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zd d!„Zd"d#„Zd$d%„Zd*d'd(„ZdS)+ÚLocatorzG A base class for locators - things that locate distributions. )z.tar.gzz.tar.bz2z.tarz.zipz.tgzz.tbz)z.eggz.exeú.whl)z.pdfN)rLÚdefaultcCs,i|_||_ttƒƒ|_d|_t ¡|_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) Ú_cacher6rr1ÚopenerÚmatcherr ÚQueueÚerrors)r;r6r.r.r/Ú__init__fs  zLocator.__init__cCsVg}|j ¡sRz|j d¡}| |¡Wn|jjk rDYqYnX|j ¡q|S)z8 Return any errors which have occurred. F)rRÚemptyÚgetÚappendÚEmptyÚ task_done)r;ÚresultÚer.r.r/Ú get_errorsys    zLocator.get_errorscCs | ¡dS)z> Clear any errors which may have been logged. N)r[©r;r.r.r/Ú clear_errors‡szLocator.clear_errorscCs|j ¡dS©N)rNÚclearr\r.r.r/Ú clear_cacheŽszLocator.clear_cachecCs|jSr^©Ú_schemer\r.r.r/Ú _get_scheme‘szLocator._get_schemecCs ||_dSr^ra)r;Ú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. ú Please implement in the subclassN©ÚNotImplementedError)r;Únamer.r.r/Ú _get_project™s zLocator._get_projectcCs tdƒ‚dS)úJ Return all the distribution names known to this locator. rfNrgr\r.r.r/Úget_distribution_names¥szLocator.get_distribution_namescCsL|jdkr| |¡}n2||jkr,|j|}n| ¡| |¡}||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)rNrjr])r;rirYr.r.r/Ú get_project«s      zLocator.get_projectcCs^t|ƒ}t |j¡}d}| d¡}| |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. TrLÚhttpszpypi.org) rÚ posixpathÚbasenameÚpathÚendswithÚdownloadable_extensionsr%r$Ú wheel_tagsr6Únetloc)r;r,ÚtrpÚ compatibleÚis_wheelZis_downloadabler.r.r/Ú score_url¼s   ÿzLocator.score_urlcCsR|}|rN| |¡}| |¡}||kr(|}||kr@t d||¡nt d||¡|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)ryÚloggerÚdebug)r;Úurl1Úurl2rYÚ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)r;ÚfilenameÚ project_namer.r.r/rászLocator.split_filenamec Csdd„}d}t|ƒ\}}}}} } |  ¡ d¡rz~t |ƒ}t ||j ƒs°t d |¡nX|dkr¾d }n ||j |ƒ}|r|j |j |jt||||| d fƒd  dd„|jDƒ¡dœ}Wn0tk r:}zt d|¡W5d}~XYnXnÄ| |j¡sZt d|¡n¨t |¡}}|jD]’}| |¡rn|dt|ƒ …}| ||¡}|s°t d|¡nH|\}}}|rÌ|||ƒrø|||t||||| d fƒdœ}|rø||d<qqn|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|ƒkSr^)r!)Zname1Zname2r.r.r/Ú same_projectïsz:Locator.convert_url_to_download_info..same_projectNzegg=z %s: version hint in fragment: %r)NNéÿÿÿÿú/rLzWheel not compatible: %sTr4z, cSs"g|]}d t|dd…ƒ¡‘qS)Ú.éN)ÚjoinÚlist)Ú.0Úvr.r.r/Ú sz8Locator.convert_url_to_download_info..)riÚversionrr,úpython-versionzinvalid path for wheel: %szNot downloadable: %sz No match for project/version: %s)rirrr,rŽú %s_digest)rÚlowerÚ startswithrzr{Ú HASHER_HASHÚmatchÚgroupsrrr$r%rtrirrrrˆÚpyverÚ ExceptionÚwarningrsrorpÚlenr)r;r,r‚rƒrYr6rurqÚparamsÚqueryÚfragÚmÚalgoÚdigestZorigpathÚwheelÚincluderZrÚextrvrirr•r.r.r/Úconvert_url_to_download_infoçs€ÿ     ÿÿú      ÿü   z$Locator.convert_url_to_download_infocCshd}d|kr6|d}dD]}||kr|||f}q6q|sddD]$}d|}||kr>|||f}qdq>|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Úmd5rr.)r;ÚinforYr£rrBr.r.r/Ú _get_digest1s  zLocator._get_digestc Cs®| d¡}| d¡}||kr,||}|j}nt|||jd}|j}| |¡|_}|d}||d|<|j|dkrœ| |j|¡|_|d |t ƒ¡  |¡||_ |||<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. rir©r6r,r£ÚurlsN) ÚpopÚmetadatarr6r§ržÚ source_urlr€Ú setdefaultÚsetÚaddÚlocator) r;rYr¦rirÚdistÚmdržr,r.r.r/Ú_update_version_dataHs   zLocator._update_version_dataFc Cs¤d}t|ƒ}|dkr td|ƒ‚t|jƒ}| |j¡|_}t d|t|ƒj ¡|  |j ¡}t |ƒdkr2g}|j } |D]z} | dkr†qxzH| | ¡s¢t d|| ¡n*|s°| | ƒjs¼| | ¡nt d| |j ¡Wqxtk rðt d|| ¡YqxXqxt |ƒd krt||jd }|r2t d |¡|d } || }|rš|jrH|j|_| d i¡ | tƒ¡|_i} | di¡} |jD]}|| krv| || |<qv| |_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)rBzsorted list: %sr„r©r£)rrr"r6rPÚ requirementrzr{ÚtyperDrmrir˜Z version_classr“Ú is_prereleaserVr–r—ÚsortedrBÚextrasrUr®Ú download_urlsr£)r;rµÚ prereleasesrYÚrr6rPÚversionsÚslistZvclsÚkrÚdÚsdr,r.r.r/Úlocate_sX      ÿ    zLocator.locate)rM)F)rDrErFrGÚsource_extensionsÚbinary_extensionsÚexcluded_extensionsrtrsrSr[r]r`rcreÚpropertyr6rjrlrmryr€rr¢r§r³rÂr.r.r.r/rKVs.   JrKcs0eZdZdZ‡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. r&r'N)ÚsuperrÇrSÚbase_urlr r-©r;r,Úkwargs©Ú __class__r.r/rS szPyPIRPCLocator.__init__cCst|j ¡ƒS©rk)r®r-r+r\r.r.r/rl«sz%PyPIRPCLocator.get_distribution_namesc Csiidœ}|j |d¡}|D]Þ}|j ||¡}|j ||¡}t|jd}|d|_|d|_| d¡|_ | dg¡|_ | d¡|_ t |ƒ}|r|d } | d |_ | | ¡|_||_|||<|D]:} | d } | | ¡} |d  |tƒ¡ | ¡| |d | <q¾q|S) Nr´Tr¨rirÚlicenseÚkeywordsÚsummaryrr,r©r£)r-Zpackage_releasesZ release_urlsZ release_datarr6rirrUrÏrÐrÑrr¬r§ržr°r­r®r¯) r;rirYr½r‹r©Údatar«r±r¦r,ržr.r.r/rj±s0         zPyPIRPCLocator._get_project©rDrErFrGrSrlrjÚ __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|ƒ|_dSr^)rÈrÕrSrrÉrÊrÌr.r/rSÐszPyPIJSONLocator.__init__cCs tdƒ‚dS©rkzNot available from this locatorNrgr\r.r.r/rlÔsz&PyPIJSONLocator.get_distribution_namesc Cs iidœ}t|jdt|ƒƒ}z¤|j |¡}| ¡ ¡}t |¡}t |j d}|d}|d|_ |d|_ |  d¡|_|  dg¡|_|  d ¡|_t|ƒ}||_|d } |||j <|d D]T} | d }|j |¡| | ¡|j|<|d  |j tƒ¡ |¡| | ¡|d |<qº|d  ¡D]¤\} } | |j kr4qt |j d} |j | _ | | _ t| ƒ}||_||| <| D]T} | d }|j |¡| | ¡|j|<|d  | tƒ¡ |¡| | ¡|d |<qhqWn@tk r}z |j t|ƒ¡t d|¡W5d}~XYnX|S)Nr´z%s/jsonr¨r¦rirrÏrÐrÑr©r,r£ZreleaseszJSON fetch failed: %s) rrÉr rOÚopenÚreadÚdecodeÚjsonÚloadsrr6rirrUrÏrÐrÑrr°rºr¯r§r£r­r®Úitemsr–rRÚputrrzÚ exception)r;rirYr,ÚresprÒrÀr²r±r©r¦rÚinfosZomdÚodistrZr.r.r/rjÚsT                zPyPIJSONLocator._get_projectrÓr.r.rÌr/rÕËs rÕc@s`eZdZdZe dejejBejB¡Z e dejejB¡Z dd„Z e dej¡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||_||_|_|j |j¡}|r0| d¡|_dS)zk Initialise an instance with the Unicode page contents and the URL they came from. rN)rÒrÉr,Ú_baseÚsearchÚgroup)r;rÒr,rœr.r.r/rS s  z Page.__init__z[^a-z0-9$&+,/:;=?@.#%_\\|-]cCs¾dd„}tƒ}|j |j¡D]Š}| d¡}|dpX|dpX|dpX|dpX|dpX|d }|d pp|d pp|d }t|j|ƒ}t|ƒ}|j  d d„|¡}|  ||f¡qt |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,r6rurqr™ršr›r.r.r/Úclean4s  ÿzPage.links..cleanr4Zrel1Zrel2Zrel3Zrel4Zrel5Zrel6r|r}Zurl3cSsdt| d¡ƒS)Nz%%%2xr)Úordrå)rœr.r.r/ÚBózPage.links..cSs|dS)Nrr.)rvr.r.r/rèFréT)rBÚreverse) r®Ú_hrefÚfinditerrÒÚ groupdictrrÉr Ú _clean_reÚsubr¯r¸)r;rærYr“rÀÚrelr,r.r.r/Úlinks-s$ ÿÿÿ z Page.linksN)rDrErFrGÚreÚcompileÚIÚSÚXrërãrSrîrrñr.r.r.r/râsü râcs˜eZdZdZejdd„dd„dœZd‡fdd „ Zd d „Zd d „Z dd„Z e   de j ¡Zdd„Zdd„Zdd„Zdd„Zdd„Ze   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 ¡S)N)Úfileobj)ÚgzipÚGzipFilerrÀrØ©Úbr.r.r/rèTrézSimpleScrapingLocator.cCs|Sr^r.rûr.r.r/rèUré)ÚdeflaterùÚnoneNé c sltt|ƒjf|Žt|ƒ|_||_i|_tƒ|_t   ¡|_ tƒ|_ d|_ ||_t ¡|_t ¡|_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÷rSrrÉr(Ú _page_cacher®Ú_seenr rQÚ _to_fetchÚ _bad_hostsÚskip_externalsÚ num_workersÚ threadingÚRLockÚ_lockÚ_gplockÚplatform_check)r;r,r(rrËrÌr.r/rSXs     zSimpleScrapingLocator.__init__cCsFg|_t|jƒD]0}tj|jd}| d¡| ¡|j |¡qdS)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ÚrangerrÚThreadÚ_fetchÚ setDaemonÚstartrV)r;Úirvr.r.r/Ú_prepare_threadsss  z&SimpleScrapingLocator._prepare_threadscCs6|jD]}|j d¡q|jD] }| ¡qg|_dS)zu Tell all the threads to terminate (by sending a sentinel value) and wait for them to do so. N)r rrÝrˆ)r;rvr.r.r/Ú _wait_threads€s    z#SimpleScrapingLocator._wait_threadsc Cs’iidœ}|jx||_||_t|jdt|ƒƒ}|j ¡|j ¡|  ¡z&t   d|¡|j  |¡|j  ¡W5|  ¡X|`W5QRX|S)Nr´z%s/z Queueing %s)r rYr‚rrÉr rr_rrrrzr{rrÝrˆ)r;rirYr,r.r.r/rjs      z"SimpleScrapingLocator._get_projectz<\b(linux_(i\d86|x86_64|arm\w+)|win(32|_amd64)|macosx_?\d+)\bcCs |j |¡S)zD Does an URL refer to a platform-specific download? )Úplatform_dependenträ)r;r,r.r.r/Ú_is_platform_dependent¢sz,SimpleScrapingLocator._is_platform_dependentc CsZ|jr| |¡rd}n| ||j¡}t d||¡|rV|j| |j|¡W5QRX|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) r rr¢r‚rzr{rr³rY)r;r,r¦r.r.r/Ú_process_download¨s z'SimpleScrapingLocator._process_downloadc CsÄt|ƒ\}}}}}}| |j|j|j¡r2d}n||jrJ| |j¡sJd}nd| |j¡s\d}nR|dkrjd}nD|dkrxd}n6| |¡rˆd}n&|  dd¡d} |   ¡dkrªd}nd}t   d ||||¡|S) z‘ Determine whether a link URL from a referring page and with a particular "rel" attribute should be queued for scraping. F)ZhomepageÚdownload)ÚhttprnÚftpú:rrÚ localhostTz#should_queue: %s (%s) from %s -> %s) rrrrÃrÄrÅrr‘rÉrÚsplitrrzr{) r;ÚlinkZreferrerrðr6rurqÚ_rYÚhostr.r.r/Ú _should_queue¼s0ÿ    ÿz#SimpleScrapingLocator._should_queuec Csð|j ¡}zÌz”|rž| |¡}|dkr,WW¢®q|jD]j\}}||jkr2zB|j |¡| |¡s„| |||¡r„t   d||¡|j  |¡Wq2t k ršYq2Xq2Wn2t k rÒ}z|j  t|ƒ¡W5d}~XYnXW5|j ¡X|sqìqdS)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)rrUrXÚget_pagerñrr¯rr!rzr{rÝrr–rRr)r;r,ÚpagerrðrZr.r.r/rÙs,      ÿ & zSimpleScrapingLocator._fetchc CsXt|ƒ\}}}}}}|dkr:tj t|ƒ¡r:tt|ƒdƒ}||jkr`|j|}t  d||¡nô|  dd¡d}d}||j krt  d||¡nÄt |d d id }z¤zât  d |¡|j j||jd } t  d|¡|  ¡} |  dd¡} t | ¡r„|  ¡} |  ¡} |  d¡}|r"|j|}|| ƒ} d}t | ¡}|r@| d¡}z|  |¡} Wn tk rn|  d¡} YnXt| | ƒ}||j| <Wn¼tk rÄ}z|jdkr´t d||¡W5d}~XYn€t k r}z0t d||¡|j!|j  "|¡W5QRXW5d}~XYn2t#k rB}zt d||¡W5d}~XYnXW5||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 %sr'z Fetched %sz Content-Typer4zContent-Encodingzutf-8zlatin-1i”zFetch failed: %s: %s)$rÚosrqÚisdirrrrrrzr{rrrrOr×r(r¦rUÚHTML_CONTENT_TYPEr“ÚgeturlrØÚdecodersÚCHARSETrärårÙÚ UnicodeErrorrârr>rÞrrr¯r–)r;r,r6rurqrrYr r<rßr@Ú content_typeZ final_urlrÒÚencodingÚdecoderrœrZr.r.r/r"úsZ              &$ zSimpleScrapingLocator.get_pagez]*>([^<]+)„sr>cs(eZdZdZ‡fdd„Zdd„Z‡ZS)ÚDistPathLocatorz‚ This locator finds installed distributions in a path. It can be useful for adding to an :class:`AggregatingLocator`. c s*tt|ƒjf|Žt|tƒs t‚||_dS)zs Initialise an instance. :param distpath: A :class:`DistributionPath` instance to search. N)rÈrDrSÚ isinstancerÚAssertionErrorÚdistpath)r;rGrËrÌr.r/rS¯szDistPathLocator.__init__cCsP|j |¡}|dkr iidœ}n,|j|d|jt|jgƒid|jtdgƒii}|S)Nr´r©r£)rGÚget_distributionrr®r¬)r;rir±rYr.r.r/rj¹s  ýzDistPathLocator._get_project)rDrErFrGrSrjrÔr.r.rÌr/rDªs rDcsReZdZdZ‡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*| dd¡|_||_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ªrJÚlocatorsrÈrIrS)r;rKrËrÌr.r/rSÊs zAggregatingLocator.__init__cs&tt|ƒ ¡|jD] }| ¡qdSr^)rÈrIr`rK©r;r°rÌr.r/r`Ús zAggregatingLocator.clear_cachecCs||_|jD] }||_q dSr^)rbrKr6)r;rdr°r.r.r/reßs zAggregatingLocator._set_schemec Csìi}|jD]Ü}| |¡}|r |jr¨| di¡}| di¡}| |¡| d¡}|rŠ|rŠ| ¡D]*\}} ||kr€||| O<q^| ||<q^| d¡} |ræ| ræ|  |¡q |jdkr¸d} n"d} |D]}|j |¡rÀd} qÚqÀ| r |}qèq |S)Nr©r£TF)rKrmrJrUÚupdaterÜrPr“) r;rirYr°rÀr<r£Zdfr¿r‹ÚddÚfoundr.r.r/rjæs8          zAggregatingLocator._get_projectc Cs<tƒ}|jD]*}z|| ¡O}Wq tk r4Yq Xq |SrÎ)r®rKrlrh)r;rYr°r.r.r/rls z)AggregatingLocator.get_distribution_names)rDrErFrGrSr`rerÆrKr6ÚfgetrjrlrÔr.r.rÌr/rIÆs  ,rIzhttps://pypi.org/simple/r&r'Úlegacyr¨z1(?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"r6rLr.r.r/rS1s zDependencyFinder.__init__cCsrt d|¡|j}||j|<||j||jf<|jD]:}t|ƒ\}}t d|||¡|j  |t ƒ¡  ||f¡q2dS)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) rzr{rBÚ dists_by_nameÚdistsrÚprovidesrÚprovidedr­r®r¯)r;r±riÚprr.r.r/Úadd_distribution9s    z!DependencyFinder.add_distributioncCsxt d|¡|j}|j|=|j||jf=|jD]D}t|ƒ\}}t d|||¡|j|}|  ||f¡|s.|j|=q.dS)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) rzr{rBrTrUrrVrrWÚremove)r;r±rirXrÚsr.r.r/Úremove_distributionHs    z$DependencyFinder.remove_distributioncCsBz|j |¡}Wn,tk r<| ¡d}|j |¡}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)r6rPr#r)r;ÚreqtrPrir.r.r/Ú get_matcherZs  zDependencyFinder.get_matcherc Cst| |¡}|j}tƒ}|j}||krp||D]B\}}z| |¡}Wntk rZd}YnX|r,| |¡qpq,|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)r^rBr®rWr“r#r¯) r;r]rPrirYrWrÚproviderr“r.r.r/Úfind_providersjs   zDependencyFinder.find_providersc Csž|j|}tƒ}|D]$}| |¡}| |j¡s| |¡q|rZ| d||t|ƒf¡d}n@| |¡|j|=|D]}|j |tƒ¡ |¡qp|  |¡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®r^r“rr¯Ú frozensetr\r­rY) r;r_ÚotherÚproblemsZrlistÚ unmatchedr[rPrYr.r.r/Útry_to_replace‚s$     ÿ  zDependencyFinder.try_to_replaceFcCsòi|_i|_i|_i|_t|p gƒ}d|krH| d¡|tdddgƒO}t|tƒrh|}}t  d|¡n4|j j ||d}}|dkrt d|ƒ‚t  d |¡d |_ tƒ}t|gƒ}t|gƒ}|r¤| ¡}|j} | |jkræ| |¡n"|j| } | |kr| || |¡|j|jB} |j} tƒ} |r`||kr`d D]*}d |}||kr4| t|d |ƒO} q4| | B| B}|D].}| |¡}|sFt  d|¡|j j ||d}|dkrÂ|sÂ|j j |d d}|dkrèt  d|¡| d|f¡n^|j|j}}||f|jkr| |¡| |¡|| krF||krF| |¡t  d|j¡|D]R}|j} | |jkrx|j |tƒ¡ |¡n"|j| } | |krJ| || |¡qJqpq¼t|j ¡ƒ}|D]&}||k|_|jr¶t  d|j¡q¶t  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)rWrUrTrar®rZrErrzr{r°rÂrÚ requestedrªrBrYrfZ run_requiresZ meta_requiresZbuild_requiresÚgetattrr`r¯rZname_and_versionr­ÚvaluesZbuild_time_dependency)r;rµZ meta_extrasr»r±rárdÚtodoZ install_distsrircZireqtsZsreqtsZereqtsrBrZZ all_reqtsr¼Z providersr_Únr‹rXrUr.r.r/Úfindªs’   ÿ                    ÿ    ÿ zDependencyFinder.find)N)NF) rDrErFrGrSrYr\r^r`rfror.r.r.r/rR,s (rR)N)OrùÚiorrÚÚloggingr&roròrÚ ImportErrorZdummy_threadingr1r4rÚcompatrrrrr r r r r rrr9rrrrZdatabaserrrr«rrÚutilrrrrrrrr r!rr"r#rŸr$r%Ú getLoggerrDrzrór’rôr+r(r*r0r1ÚobjectrKrÇrÕrâr÷r3r>rDrIrSrÂÚNAME_VERSION_RErRr.r.r.r/Ús^   D,    G0E:zA&[ÿü