class MockPackageFinder: BASE_URL = "https://pypi.org/simple/pip-{0}.tar.gz" PIP_PROJECT_NAME = "pip" INSTALLATION_CANDIDATES = [ InstallationCandidate( PIP_PROJECT_NAME, "6.9.0", Link(BASE_URL.format("6.9.0")), ), InstallationCandidate( PIP_PROJECT_NAME, "3.3.1", Link(BASE_URL.format("3.3.1")), ), InstallationCandidate( PIP_PROJECT_NAME, "1.0", Link(BASE_URL.format("1.0")), ), ] @classmethod def create(cls, *args: Any, **kwargs: Any) -> "MockPackageFinder": return cls() def find_best_candidate(self, project_name: str) -> MockBestCandidateResult: return MockBestCandidateResult(self.INSTALLATION_CANDIDATES[0])
class MockPackageFinder(object): BASE_URL = 'https://pypi.org/simple/pip-{0}.tar.gz' PIP_PROJECT_NAME = 'pip' INSTALLATION_CANDIDATES = [ InstallationCandidate(PIP_PROJECT_NAME, '6.9.0', BASE_URL.format('6.9.0')), InstallationCandidate(PIP_PROJECT_NAME, '3.3.1', BASE_URL.format('3.3.1')), InstallationCandidate(PIP_PROJECT_NAME, '1.0', BASE_URL.format('1.0')), ] @classmethod def create(cls, *args, **kwargs): return cls() def find_best_candidate(self, project_name): return MockBestCandidateResult(self.INSTALLATION_CANDIDATES[0])
def setUp(self): candidates = [] for version in canned_versions: url = "https://foo:12345/repository/unittest-{}.tgz#md5=4711".format( version) url = Link(url) candidate = InstallationCandidate('unittest', version, url) candidates.append(candidate) self.canned_candidates = candidates
def make_mock_candidate(version, yanked_reason=None, hex_digest=None): url = 'https://example.com/pkg-{}.tar.gz'.format(version) if hex_digest is not None: assert len(hex_digest) == 64 url += '#sha256={}'.format(hex_digest) link = Link(url, yanked_reason=yanked_reason) candidate = InstallationCandidate('mypackage', version, link) return candidate
def make_mock_candidate(version, yanked_reason=None, hex_digest=None): url = f"https://example.com/pkg-{version}.tar.gz" if hex_digest is not None: assert len(hex_digest) == 64 url += f"#sha256={hex_digest}" link = Link(url, yanked_reason=yanked_reason) candidate = InstallationCandidate("mypackage", version, link) return candidate
def test_sort_key__is_yanked(self, yanked_reason, expected): """ Test the effect of is_yanked on _sort_key()'s return value. """ url = 'https://example.com/mypackage.tar.gz' link = Link(url, yanked_reason=yanked_reason) candidate = InstallationCandidate('mypackage', '1.0', link) evaluator = CandidateEvaluator() sort_value = evaluator._sort_key(candidate) # Yanked / non-yanked is reflected in the first element of the tuple. actual = sort_value[0] assert actual == expected
def test_collect_sources( self, caplog: pytest.LogCaptureFixture, data: TestData ) -> None: caplog.set_level(logging.DEBUG) link_collector = make_test_link_collector( find_links=[data.find_links], # Include two copies of the URL to check that the second one # is skipped. index_urls=[PyPI.simple_url, PyPI.simple_url], ) collected_sources = link_collector.collect_sources( "twine", candidates_from_page=lambda link: [ InstallationCandidate("twine", "1.0", link) ], ) files_it = itertools.chain.from_iterable( source.file_links() for sources in collected_sources for source in sources if source is not None ) pages_it = itertools.chain.from_iterable( source.page_candidates() for sources in collected_sources for source in sources if source is not None ) files = list(files_it) pages = list(pages_it) # Spot-check the returned sources. assert len(files) > 20 check_links_include(files, names=["simple-1.0.tar.gz"]) assert [page.link for page in pages] == [Link("https://pypi.org/simple/twine/")] # Check that index URLs are marked as *un*cacheable. assert not pages[0].link.cache_link_parsing expected_message = dedent( """\ 1 location(s) to search for versions of twine: * https://pypi.org/simple/twine/""" ) assert caplog.record_tuples == [ ("pip._internal.index.collector", logging.DEBUG, expected_message), ]
def test_provider_known_depths(factory: Factory) -> None: # Root requirement is specified by the user # therefore has an infered depth of 1 root_requirement_name = "my-package" provider = PipProvider( factory=factory, constraints={}, ignore_dependencies=False, upgrade_strategy="to-satisfy-only", user_requested={root_requirement_name: 0}, ) root_requirement_information = build_requirement_information( name=root_requirement_name, parent=None) provider.get_preference( identifier=root_requirement_name, resolutions={}, candidates={}, information={root_requirement_name: root_requirement_information}, backtrack_causes=[], ) assert provider._known_depths == {root_requirement_name: 1.0} # Transative requirement is a dependency of root requirement # theforefore has an infered depth of 2 root_package_candidate = InstallationCandidate( root_requirement_name, "1.0", Link("https://{root_requirement_name}.com"), ) transative_requirement_name = "my-transitive-package" transative_package_information = build_requirement_information( name=transative_requirement_name, parent=root_package_candidate) provider.get_preference( identifier=transative_requirement_name, resolutions={}, candidates={}, information={ root_requirement_name: root_requirement_information, transative_requirement_name: transative_package_information, }, backtrack_causes=[], ) assert provider._known_depths == { transative_requirement_name: 2.0, root_requirement_name: 1.0, }
def get_install_candidate(self, link_evaluator: LinkEvaluator, link: Link) -> Optional[InstallationCandidate]: """ If the link is a candidate for install, convert it to an InstallationCandidate and return it. Otherwise, return None. """ result, detail = link_evaluator.evaluate_link(link) if result != LinkType.candidate: self._log_skipped_link(link, result, detail) return None return InstallationCandidate( name=link_evaluator.project_name, link=link, version=detail, )
def find_best_match(self, ireq, prereleases=False): if ireq.editable: return ireq versions = list( ireq.specifier.filter( self.index[key_from_ireq(ireq)], prereleases=prereleases ) ) if not versions: tried_versions = [ InstallationCandidate(ireq.name, version, "https://fake.url.foo") for version in self.index[key_from_ireq(ireq)] ] raise NoCandidateFound(ireq, tried_versions, ["https://fake.url.foo"]) best_version = max(versions, key=Version) return make_install_requirement(key_from_ireq(ireq), best_version, ireq)
def get_install_candidate(self, link, search): # type: (Link, Search) -> Optional[InstallationCandidate] """ If the link is a candidate for install, convert it to an InstallationCandidate and return it. Otherwise, return None. """ is_candidate, result = self._evaluate_link(link, search=search) if not is_candidate: if result: self._log_skipped_link(link, reason=result) return None return InstallationCandidate( search.supplied, location=link, version=result, )
def _pip_query_pypi_json(resconfig): package_name = resconfig['source']['name'] index_url, unused_hostname = get_pypi_url(resconfig) url = '{}/{}/json'.format(index_url, package_name) response = requests.get(url) if response.ok: candidates = [] data = response.json() for version, release_artefacts in data['releases'].items(): for release in release_artefacts: candidates.append( InstallationCandidate(package_name, version, Link(release['url']))) return candidates return None
def get_install_candidate(self, link_evaluator, link): # type: (LinkEvaluator, Link) -> Optional[InstallationCandidate] """ If the link is a candidate for install, convert it to an InstallationCandidate and return it. Otherwise, return None. """ is_candidate, result = link_evaluator.evaluate_link(link) if not is_candidate: if result: self._log_skipped_link(link, reason=result) return None return InstallationCandidate( name=link_evaluator.project_name, link=link, version=result, )
def get_install_candidate(self, link, search): # type: (Link, Search) -> Optional[InstallationCandidate] """ If the link is a candidate for install, convert it to an InstallationCandidate and return it. Otherwise, return None. """ is_candidate, result = ( self.candidate_evaluator.evaluate_link(link, search=search) ) if not is_candidate: if result: self._log_skipped_link(link, reason=result) return None return InstallationCandidate( # Convert the Text result to str since InstallationCandidate # accepts str. search.supplied, location=link, version=str(result), )
def get_install_candidate(self, link_evaluator, link): # type: (LinkEvaluator, Link) -> Optional[InstallationCandidate] """ If the link is a candidate for install, convert it to an InstallationCandidate and return it. Otherwise, return None. """ is_candidate, result = link_evaluator.evaluate_link(link) if not is_candidate: if result: self._log_skipped_link(link, reason=result) return None return InstallationCandidate( project=link_evaluator.project_name, location=link, # Convert the Text result to str since InstallationCandidate # accepts str. version=str(result), )
def evaluate_link(self, link, search): # type: (Link, Search) -> Optional[InstallationCandidate] """ Determine whether a link is a candidate for installation. Returns an InstallationCandidate if so, otherwise None. """ version = None if link.egg_fragment: egg_info = link.egg_fragment ext = link.ext else: egg_info, ext = link.splitext() if not ext: self._log_skipped_link(link, 'not a file') return None if ext not in SUPPORTED_EXTENSIONS: self._log_skipped_link( link, 'unsupported archive format: %s' % ext, ) return None if "binary" not in search.formats and ext == WHEEL_EXTENSION: self._log_skipped_link( link, 'No binaries permitted for %s' % search.supplied, ) return None if "macosx10" in link.path and ext == '.zip': self._log_skipped_link(link, 'macosx10 one') return None if ext == WHEEL_EXTENSION: try: wheel = Wheel(link.filename) except InvalidWheelFilename: self._log_skipped_link(link, 'invalid wheel filename') return None if canonicalize_name(wheel.name) != search.canonical: self._log_skipped_link( link, 'wrong project name (not %s)' % search.supplied) return None if not self._is_wheel_supported(wheel): self._log_skipped_link( link, 'it is not compatible with this Python') return None version = wheel.version # This should be up by the search.ok_binary check, but see issue 2700. if "source" not in search.formats and ext != WHEEL_EXTENSION: self._log_skipped_link( link, 'No sources permitted for %s' % search.supplied, ) return None if not version: version = _egg_info_matches(egg_info, search.canonical) if not version: self._log_skipped_link( link, 'Missing project version for %s' % search.supplied) return None match = self._py_version_re.search(version) if match: version = version[:match.start()] py_version = match.group(1) if py_version != sys.version[:3]: self._log_skipped_link(link, 'Python version is incorrect') return None try: support_this_python = check_requires_python( link.requires_python, version_info=sys.version_info[:3], ) except specifiers.InvalidSpecifier: logger.debug("Package %s has an invalid Requires-Python entry: %s", link.filename, link.requires_python) support_this_python = True if not support_this_python: logger.debug( "The package %s is incompatible with the python " "version in use. Acceptable python versions are: %s", link, link.requires_python) return None logger.debug('Found link %s, version: %s', link, version) return InstallationCandidate(search.supplied, version, link)
def _link_package_versions(self, link, search): """Return an InstallationCandidate or None""" version = None if link.egg_fragment: egg_info = link.egg_fragment ext = link.ext else: egg_info, ext = link.splitext() if not ext: self._log_skipped_link(link, "not a file") return if ext not in SUPPORTED_EXTENSIONS: self._log_skipped_link(link, "unsupported archive format: %s" % ext) return if "binary" not in search.formats and ext == wheel_ext: self._log_skipped_link( link, "No binaries permitted for %s" % search.supplied) return if "macosx10" in link.path and ext == ".zip": self._log_skipped_link(link, "macosx10 one") return if ext == wheel_ext: try: wheel = Wheel(link.filename) except InvalidWheelFilename: self._log_skipped_link(link, "invalid wheel filename") return if canonicalize_name(wheel.name) != search.canonical: self._log_skipped_link( link, "wrong project name (not %s)" % search.supplied) return if not wheel.supported(self.valid_tags): self._log_skipped_link( link, "it is not compatible with this Python") return version = wheel.version # This should be up by the search.ok_binary check, but see issue 2700. if "source" not in search.formats and ext != wheel_ext: self._log_skipped_link( link, "No sources permitted for %s" % search.supplied) return if not version: version = egg_info_matches(egg_info, search.supplied, link) if version is None: self._log_skipped_link( link, "Missing project version for %s" % search.supplied) return match = self._py_version_re.search(version) if match: version = version[:match.start()] py_version = match.group(1) if py_version != sys.version[:3]: self._log_skipped_link(link, "Python version is incorrect") return try: support_this_python = check_requires_python(link.requires_python) except specifiers.InvalidSpecifier: logger.debug( "Package %s has an invalid Requires-Python entry: %s", link.filename, link.requires_python, ) support_this_python = True if not support_this_python: logger.debug( "The package %s is incompatible with the python" "version in use. Acceptable python versions are:%s", link, link.requires_python, ) return logger.debug("Found link %s, version: %s", link, version) return InstallationCandidate(search.supplied, version, link)
def make_mock_candidate(self, version, yanked_reason=None): url = 'https://example.com/pkg-{}.tar.gz'.format(version) link = Link(url, yanked_reason=yanked_reason) candidate = InstallationCandidate('mypackage', version, link) return candidate