diff --git a/src/pip/_internal/resolution/resolvelib/base.py b/src/pip/_internal/resolution/resolvelib/base.py index 5f99618ce..c87b9da06 100644 --- a/src/pip/_internal/resolution/resolvelib/base.py +++ b/src/pip/_internal/resolution/resolvelib/base.py @@ -6,6 +6,7 @@ if MYPY_CHECK_RUNNING: from typing import Optional, Sequence, Set from pip._internal.req.req_install import InstallRequirement + from pip._vendor.packaging.specifiers import SpecifierSet from pip._vendor.packaging.version import _BaseVersion @@ -23,8 +24,8 @@ class Requirement(object): # type: () -> str raise NotImplementedError("Subclass should override") - def find_matches(self): - # type: () -> Sequence[Candidate] + def find_matches(self, constraints): + # type: (Sequence[SpecifierSet]) -> Sequence[Candidate] raise NotImplementedError("Subclass should override") def is_satisfied_by(self, candidate): diff --git a/src/pip/_internal/resolution/resolvelib/factory.py b/src/pip/_internal/resolution/resolvelib/factory.py index 0f69a14df..123222281 100644 --- a/src/pip/_internal/resolution/resolvelib/factory.py +++ b/src/pip/_internal/resolution/resolvelib/factory.py @@ -21,7 +21,7 @@ from .requirements import ( ) if MYPY_CHECK_RUNNING: - from typing import Dict, Iterator, List, Optional, Set, Tuple, TypeVar + from typing import Dict, Iterator, Optional, Set, Tuple, TypeVar from pip._vendor.packaging.specifiers import SpecifierSet from pip._vendor.packaging.version import _BaseVersion @@ -79,8 +79,6 @@ class Factory(object): else: self._installed_dists = {} - self._constraints = {} # type: Dict[str,List[SpecifierSet]] - def _make_candidate_from_dist( self, dist, # type: Distribution diff --git a/src/pip/_internal/resolution/resolvelib/provider.py b/src/pip/_internal/resolution/resolvelib/provider.py index 5c3d210a3..0fe9b9771 100644 --- a/src/pip/_internal/resolution/resolvelib/provider.py +++ b/src/pip/_internal/resolution/resolvelib/provider.py @@ -3,7 +3,9 @@ from pip._vendor.resolvelib.providers import AbstractProvider from pip._internal.utils.typing import MYPY_CHECK_RUNNING if MYPY_CHECK_RUNNING: - from typing import Any, Optional, Sequence, Tuple, Union + from typing import Any, Dict, List, Optional, Sequence, Tuple, Union + + from pip._vendor.packaging.specifiers import SpecifierSet from pip._internal.req.req_install import InstallRequirement @@ -15,10 +17,12 @@ class PipProvider(AbstractProvider): def __init__( self, factory, # type: Factory + constraints, # type: Dict[str,List[SpecifierSet]] ignore_dependencies, # type: bool ): # type: (...) -> None self._factory = factory + self._constraints = constraints self._ignore_dependencies = ignore_dependencies def get_install_requirement(self, c): @@ -41,7 +45,8 @@ class PipProvider(AbstractProvider): def find_matches(self, requirement): # type: (Requirement) -> Sequence[Candidate] - return requirement.find_matches() + constraints = self._constraints.get(requirement.name, []) + return requirement.find_matches(constraints) def is_satisfied_by(self, requirement, candidate): # type: (Requirement, Candidate) -> bool diff --git a/src/pip/_internal/resolution/resolvelib/requirements.py b/src/pip/_internal/resolution/resolvelib/requirements.py index 1c4c54398..92ddd0480 100644 --- a/src/pip/_internal/resolution/resolvelib/requirements.py +++ b/src/pip/_internal/resolution/resolvelib/requirements.py @@ -35,9 +35,9 @@ class ExplicitRequirement(Requirement): # No need to canonicalise - the candidate did this return self.candidate.name - def find_matches(self): - # type: () -> Sequence[Candidate] - if self.name in self._factory._constraints: + def find_matches(self, constraints): + # type: (Sequence[SpecifierSet]) -> Sequence[Candidate] + if constraints: raise InstallationError( "Could not satisfy constraints for '{}': " "installation from path or url cannot be " @@ -75,14 +75,12 @@ class SpecifierRequirement(Requirement): canonical_name = canonicalize_name(self._ireq.req.name) return format_name(canonical_name, self.extras) - def find_matches(self): - # type: () -> Sequence[Candidate] + def find_matches(self, constraints): + # type: (Sequence[SpecifierSet]) -> Sequence[Candidate] it = self._factory.iter_found_candidates(self._ireq, self.extras) - constraints = self._factory._constraints.get(self.name, []) - lit = [c for c in it if all( + return [c for c in it if all( s.contains(c.version, prereleases=True) for s in constraints )] - return lit def is_satisfied_by(self, candidate): # type: (Candidate) -> bool @@ -116,8 +114,8 @@ class RequiresPythonRequirement(Requirement): # type: () -> str return self._candidate.name - def find_matches(self): - # type: () -> Sequence[Candidate] + def find_matches(self, constraints): + # type: (Sequence[SpecifierSet]) -> Sequence[Candidate] if self._candidate.version in self.specifier: return [self._candidate] return [] diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py index 94d6046b6..86e2ab953 100644 --- a/src/pip/_internal/resolution/resolvelib/resolver.py +++ b/src/pip/_internal/resolution/resolvelib/resolver.py @@ -84,11 +84,9 @@ class Resolver(BaseResolver): self.factory.make_requirement_from_install_req(req) ) - # TODO: Refactor this, it's just for proof of concept - self.factory._constraints = constraints - provider = PipProvider( factory=self.factory, + constraints=constraints, ignore_dependencies=self.ignore_dependencies, ) reporter = BaseReporter() diff --git a/tests/unit/resolution_resolvelib/conftest.py b/tests/unit/resolution_resolvelib/conftest.py index 11278fa85..41c479bf3 100644 --- a/tests/unit/resolution_resolvelib/conftest.py +++ b/tests/unit/resolution_resolvelib/conftest.py @@ -64,5 +64,6 @@ def factory(finder, preparer): def provider(factory): yield PipProvider( factory=factory, + constraints={}, ignore_dependencies=False, ) diff --git a/tests/unit/resolution_resolvelib/test_requirement.py b/tests/unit/resolution_resolvelib/test_requirement.py index ad54df00b..e25f44c4a 100644 --- a/tests/unit/resolution_resolvelib/test_requirement.py +++ b/tests/unit/resolution_resolvelib/test_requirement.py @@ -58,14 +58,14 @@ def test_new_resolver_correct_number_of_matches(test_cases, factory): """Requirements should return the correct number of candidates""" for spec, name, matches in test_cases: req = factory.make_requirement_from_spec(spec, comes_from=None) - assert len(req.find_matches()) == matches + assert len(req.find_matches([])) == matches def test_new_resolver_candidates_match_requirement(test_cases, factory): """Candidates returned from find_matches should satisfy the requirement""" for spec, name, matches in test_cases: req = factory.make_requirement_from_spec(spec, comes_from=None) - for c in req.find_matches(): + for c in req.find_matches([]): assert isinstance(c, Candidate) assert req.is_satisfied_by(c)