mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
Merge constraints into a single SpecifierSet
This commit is contained in:
parent
ee4830b5ec
commit
64b3d1b278
|
@ -24,8 +24,8 @@ class Requirement(object):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
raise NotImplementedError("Subclass should override")
|
raise NotImplementedError("Subclass should override")
|
||||||
|
|
||||||
def find_matches(self, constraints):
|
def find_matches(self, constraint):
|
||||||
# type: (Sequence[SpecifierSet]) -> Sequence[Candidate]
|
# type: (SpecifierSet) -> Sequence[Candidate]
|
||||||
raise NotImplementedError("Subclass should override")
|
raise NotImplementedError("Subclass should override")
|
||||||
|
|
||||||
def is_satisfied_by(self, candidate):
|
def is_satisfied_by(self, candidate):
|
||||||
|
|
|
@ -182,7 +182,7 @@ class Factory(object):
|
||||||
cand = self._make_candidate_from_link(
|
cand = self._make_candidate_from_link(
|
||||||
ireq.link, extras=set(ireq.extras), parent=ireq,
|
ireq.link, extras=set(ireq.extras), parent=ireq,
|
||||||
)
|
)
|
||||||
return ExplicitRequirement(cand, factory=self)
|
return ExplicitRequirement(cand)
|
||||||
return SpecifierRequirement(ireq, factory=self)
|
return SpecifierRequirement(ireq, factory=self)
|
||||||
|
|
||||||
def make_requirement_from_spec(self, specifier, comes_from):
|
def make_requirement_from_spec(self, specifier, comes_from):
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
|
from pip._vendor.packaging.specifiers import SpecifierSet
|
||||||
from pip._vendor.resolvelib.providers import AbstractProvider
|
from pip._vendor.resolvelib.providers import AbstractProvider
|
||||||
|
|
||||||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
||||||
|
|
||||||
if MYPY_CHECK_RUNNING:
|
if MYPY_CHECK_RUNNING:
|
||||||
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
from typing import Any, Dict, Optional, Sequence, Tuple, Union
|
||||||
|
|
||||||
from pip._vendor.packaging.specifiers import SpecifierSet
|
|
||||||
|
|
||||||
from pip._internal.req.req_install import InstallRequirement
|
from pip._internal.req.req_install import InstallRequirement
|
||||||
|
|
||||||
|
@ -17,7 +16,7 @@ class PipProvider(AbstractProvider):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
factory, # type: Factory
|
factory, # type: Factory
|
||||||
constraints, # type: Dict[str,List[SpecifierSet]]
|
constraints, # type: Dict[str, SpecifierSet]
|
||||||
ignore_dependencies, # type: bool
|
ignore_dependencies, # type: bool
|
||||||
):
|
):
|
||||||
# type: (...) -> None
|
# type: (...) -> None
|
||||||
|
@ -45,8 +44,8 @@ class PipProvider(AbstractProvider):
|
||||||
|
|
||||||
def find_matches(self, requirement):
|
def find_matches(self, requirement):
|
||||||
# type: (Requirement) -> Sequence[Candidate]
|
# type: (Requirement) -> Sequence[Candidate]
|
||||||
constraints = self._constraints.get(requirement.name, [])
|
constraint = self._constraints.get(requirement.name, SpecifierSet())
|
||||||
return requirement.find_matches(constraints)
|
return requirement.find_matches(constraint)
|
||||||
|
|
||||||
def is_satisfied_by(self, requirement, candidate):
|
def is_satisfied_by(self, requirement, candidate):
|
||||||
# type: (Requirement, Candidate) -> bool
|
# type: (Requirement, Candidate) -> bool
|
||||||
|
|
|
@ -17,10 +17,9 @@ if MYPY_CHECK_RUNNING:
|
||||||
|
|
||||||
|
|
||||||
class ExplicitRequirement(Requirement):
|
class ExplicitRequirement(Requirement):
|
||||||
def __init__(self, candidate, factory):
|
def __init__(self, candidate):
|
||||||
# type: (Candidate, Factory) -> None
|
# type: (Candidate) -> None
|
||||||
self.candidate = candidate
|
self.candidate = candidate
|
||||||
self._factory = factory
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
|
@ -35,9 +34,9 @@ class ExplicitRequirement(Requirement):
|
||||||
# No need to canonicalise - the candidate did this
|
# No need to canonicalise - the candidate did this
|
||||||
return self.candidate.name
|
return self.candidate.name
|
||||||
|
|
||||||
def find_matches(self, constraints):
|
def find_matches(self, constraint):
|
||||||
# type: (Sequence[SpecifierSet]) -> Sequence[Candidate]
|
# type: (Sequence[SpecifierSet]) -> Sequence[Candidate]
|
||||||
if constraints:
|
if len(constraint) > 0:
|
||||||
raise InstallationError(
|
raise InstallationError(
|
||||||
"Could not satisfy constraints for '{}': "
|
"Could not satisfy constraints for '{}': "
|
||||||
"installation from path or url cannot be "
|
"installation from path or url cannot be "
|
||||||
|
@ -75,12 +74,15 @@ class SpecifierRequirement(Requirement):
|
||||||
canonical_name = canonicalize_name(self._ireq.req.name)
|
canonical_name = canonicalize_name(self._ireq.req.name)
|
||||||
return format_name(canonical_name, self.extras)
|
return format_name(canonical_name, self.extras)
|
||||||
|
|
||||||
def find_matches(self, constraints):
|
def find_matches(self, constraint):
|
||||||
# type: (Sequence[SpecifierSet]) -> Sequence[Candidate]
|
# type: (SpecifierSet) -> Sequence[Candidate]
|
||||||
it = self._factory.iter_found_candidates(self._ireq, self.extras)
|
return [
|
||||||
return [c for c in it if all(
|
c
|
||||||
s.contains(c.version, prereleases=True) for s in constraints
|
for c in self._factory.iter_found_candidates(
|
||||||
)]
|
self._ireq, self.extras
|
||||||
|
)
|
||||||
|
if constraint.contains(c.version, prereleases=True)
|
||||||
|
]
|
||||||
|
|
||||||
def is_satisfied_by(self, candidate):
|
def is_satisfied_by(self, candidate):
|
||||||
# type: (Candidate) -> bool
|
# type: (Candidate) -> bool
|
||||||
|
@ -114,8 +116,10 @@ class RequiresPythonRequirement(Requirement):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
return self._candidate.name
|
return self._candidate.name
|
||||||
|
|
||||||
def find_matches(self, constraints):
|
def find_matches(self, constraint):
|
||||||
# type: (Sequence[SpecifierSet]) -> Sequence[Candidate]
|
# type: (Sequence[SpecifierSet]) -> Sequence[Candidate]
|
||||||
|
assert len(constraint) == 0, \
|
||||||
|
"RequiresPythonRequirement cannot have constraints"
|
||||||
if self._candidate.version in self.specifier:
|
if self._candidate.version in self.specifier:
|
||||||
return [self._candidate]
|
return [self._candidate]
|
||||||
return []
|
return []
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import functools
|
import functools
|
||||||
import logging
|
import logging
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
from pip._vendor import six
|
from pip._vendor import six
|
||||||
from pip._vendor.packaging.utils import canonicalize_name
|
from pip._vendor.packaging.utils import canonicalize_name
|
||||||
|
@ -71,14 +70,17 @@ class Resolver(BaseResolver):
|
||||||
# The persistent state that we care about is `root_reqs`.
|
# The persistent state that we care about is `root_reqs`.
|
||||||
assert len(self.factory.root_reqs) == 0, "Factory is being re-used"
|
assert len(self.factory.root_reqs) == 0, "Factory is being re-used"
|
||||||
|
|
||||||
constraints = defaultdict(list) # type: Dict[str,List[SpecifierSet]]
|
constraints = {} # type: Dict[str, SpecifierSet]
|
||||||
requirements = []
|
requirements = []
|
||||||
for req in root_reqs:
|
for req in root_reqs:
|
||||||
if req.constraint:
|
if req.constraint:
|
||||||
assert req.name
|
assert req.name
|
||||||
assert req.specifier
|
assert req.specifier
|
||||||
name = canonicalize_name(req.name)
|
name = canonicalize_name(req.name)
|
||||||
constraints[name].append(req.specifier)
|
if name in constraints:
|
||||||
|
constraints[name] = constraints[name] & req.specifier
|
||||||
|
else:
|
||||||
|
constraints[name] = req.specifier
|
||||||
else:
|
else:
|
||||||
requirements.append(
|
requirements.append(
|
||||||
self.factory.make_requirement_from_install_req(req)
|
self.factory.make_requirement_from_install_req(req)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
from pip._vendor.packaging.specifiers import SpecifierSet
|
||||||
from pip._vendor.resolvelib import BaseReporter, Resolver
|
from pip._vendor.resolvelib import BaseReporter, Resolver
|
||||||
|
|
||||||
from pip._internal.resolution.resolvelib.base import Candidate
|
from pip._internal.resolution.resolvelib.base import Candidate
|
||||||
|
@ -58,14 +59,14 @@ def test_new_resolver_correct_number_of_matches(test_cases, factory):
|
||||||
"""Requirements should return the correct number of candidates"""
|
"""Requirements should return the correct number of candidates"""
|
||||||
for spec, name, matches in test_cases:
|
for spec, name, matches in test_cases:
|
||||||
req = factory.make_requirement_from_spec(spec, comes_from=None)
|
req = factory.make_requirement_from_spec(spec, comes_from=None)
|
||||||
assert len(req.find_matches([])) == matches
|
assert len(req.find_matches(SpecifierSet())) == matches
|
||||||
|
|
||||||
|
|
||||||
def test_new_resolver_candidates_match_requirement(test_cases, factory):
|
def test_new_resolver_candidates_match_requirement(test_cases, factory):
|
||||||
"""Candidates returned from find_matches should satisfy the requirement"""
|
"""Candidates returned from find_matches should satisfy the requirement"""
|
||||||
for spec, name, matches in test_cases:
|
for spec, name, matches in test_cases:
|
||||||
req = factory.make_requirement_from_spec(spec, comes_from=None)
|
req = factory.make_requirement_from_spec(spec, comes_from=None)
|
||||||
for c in req.find_matches([]):
|
for c in req.find_matches(SpecifierSet()):
|
||||||
assert isinstance(c, Candidate)
|
assert isinstance(c, Candidate)
|
||||||
assert req.is_satisfied_by(c)
|
assert req.is_satisfied_by(c)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue