diff --git a/src/pip/_internal/resolution/resolvelib/candidates.py b/src/pip/_internal/resolution/resolvelib/candidates.py index da11c4fe7..04cd904b3 100644 --- a/src/pip/_internal/resolution/resolvelib/candidates.py +++ b/src/pip/_internal/resolution/resolvelib/candidates.py @@ -238,9 +238,21 @@ class LinkCandidate(_InstallRequirementBackedCandidate): version=None, # type: Optional[_BaseVersion] ): # type: (...) -> None + cache_entry = factory.get_wheel_cache_entry(link, name) + if cache_entry is not None: + logger.debug("Using cached wheel link: %s", cache_entry.link) + link = cache_entry.link + ireq = make_install_req_from_link(link, parent) + + # TODO: Is this logic setting original_link_is_in_wheel_cache correct? + if (cache_entry is not None and + cache_entry.persistent and + parent.link is parent.original_link): + ireq.original_link_is_in_wheel_cache = True + super(LinkCandidate, self).__init__( link=link, - ireq=make_install_req_from_link(link, parent), + ireq=ireq, factory=factory, name=name, version=version, diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py index 0c976204e..75aa4dd1c 100644 --- a/src/pip/_internal/resolution/resolvelib/factory.py +++ b/src/pip/_internal/resolution/resolvelib/factory.py @@ -8,6 +8,7 @@ from pip._internal.exceptions import ( InstallationError, UnsupportedPythonVersion, ) +from pip._internal.utils.compatibility_tags import get_supported from pip._internal.utils.misc import ( dist_in_site_packages, dist_in_usersite, @@ -37,6 +38,7 @@ if MYPY_CHECK_RUNNING: from pip._vendor.pkg_resources import Distribution from pip._vendor.resolvelib import ResolutionImpossible + from pip._internal.cache import CacheEntry, WheelCache from pip._internal.index.package_finder import PackageFinder from pip._internal.models.link import Link from pip._internal.operations.prepare import RequirementPreparer @@ -60,6 +62,7 @@ class Factory(object): finder, # type: PackageFinder preparer, # type: RequirementPreparer make_install_req, # type: InstallRequirementProvider + wheel_cache, # type: Optional[WheelCache] use_user_site, # type: bool force_reinstall, # type: bool ignore_installed, # type: bool @@ -70,6 +73,7 @@ class Factory(object): self.finder = finder self.preparer = preparer + self._wheel_cache = wheel_cache self._python_candidate = RequiresPythonCandidate(py_version_info) self._make_install_req_from_spec = make_install_req self._use_user_site = use_user_site @@ -218,6 +222,24 @@ class Factory(object): return None return RequiresPythonRequirement(specifier, self._python_candidate) + def get_wheel_cache_entry(self, link, name): + # type: (Link, Optional[str]) -> Optional[CacheEntry] + """Look up the link in the wheel cache. + + If ``preparer.require_hashes`` is True, don't use the wheel cache, + because cached wheels, always built locally, have different hashes + than the files downloaded from the index server and thus throw false + hash mismatches. Furthermore, cached wheels at present have + undeterministic contents due to file modification times. + """ + if self._wheel_cache is None or self.preparer.require_hashes: + return None + return self._wheel_cache.get_cache_entry( + link=link, + package_name=name, + supported_tags=get_supported(), + ) + def should_reinstall(self, candidate): # type: (Candidate) -> bool # TODO: Are there more cases this needs to return True? Editable? diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py index 9eab87b3a..0e55357b8 100644 --- a/src/pip/_internal/resolution/resolvelib/resolver.py +++ b/src/pip/_internal/resolution/resolvelib/resolver.py @@ -88,6 +88,7 @@ class Resolver(BaseResolver): finder=finder, preparer=preparer, make_install_req=make_install_req, + wheel_cache=wheel_cache, use_user_site=use_user_site, force_reinstall=force_reinstall, ignore_installed=ignore_installed, diff --git a/tests/unit/resolution_resolvelib/conftest.py b/tests/unit/resolution_resolvelib/conftest.py index ba3090362..87f5d129c 100644 --- a/tests/unit/resolution_resolvelib/conftest.py +++ b/tests/unit/resolution_resolvelib/conftest.py @@ -52,6 +52,7 @@ def factory(finder, preparer): finder=finder, preparer=preparer, make_install_req=install_req_from_line, + wheel_cache=None, use_user_site=False, force_reinstall=False, ignore_installed=False,