3
from .crawler import Crawler
4
from .fetcher import PyPIFetcher
5
from .package import EggPackage, Package, SourcePackage, WheelPackage
8
class Iterator(object):
9
"""A requirement iterator."""
11
DEFAULT_PACKAGE_PRECEDENCE = (
18
def package_type_precedence(cls, package, precedence=DEFAULT_PACKAGE_PRECEDENCE):
19
for rank, package_type in enumerate(reversed(precedence)):
20
if isinstance(package, package_type):
22
# If we do not recognize the package, it gets lowest precedence
26
def package_precedence(cls, package, precedence=DEFAULT_PACKAGE_PRECEDENCE):
28
package.version, # highest version
29
cls.package_type_precedence(package, precedence=precedence), # type preference
30
package.local) # prefer not fetching over the wire
32
def __init__(self, fetchers=None, crawler=None, precedence=None):
33
self._crawler = crawler or Crawler()
34
self._fetchers = fetchers or [PyPIFetcher()]
35
self._precedence = precedence or self.DEFAULT_PACKAGE_PRECEDENCE
37
def _translate_href(self, href):
38
package = Package.from_href(href)
39
# Restrict this to a package found in the package precedence list, so that users of
40
# obtainers can restrict which distribution formats they support.
41
if any(isinstance(package, package_type) for package_type in self._precedence):
44
def iter_requirement_urls(self, req):
45
return itertools.chain.from_iterable(fetcher.urls(req) for fetcher in self._fetchers)
47
def _iter_unordered(self, req, follow_links):
48
url_iterator = self.iter_requirement_urls(req)
49
crawled_url_iterator = self._crawler.crawl(url_iterator, follow_links=follow_links)
50
for package in filter(None, map(self._translate_href, crawled_url_iterator)):
51
if package.satisfies(req):
54
def _sort(self, package_list):
55
key = lambda package: self.package_precedence(package, self._precedence)
56
return sorted(package_list, key=key, reverse=True)
58
def iter(self, req, follow_links=False):
59
"""Return a list of packages that satisfy the requirement in best match order."""
60
for package in self._sort(self._iter_unordered(req, follow_links)):