Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade vendored resolvelib to 0.6.0 #9771

Merged
merged 3 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion news/resolvelib.vendor.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Upgrade vendored resolvelib to 0.5.5.
Upgrade vendored resolvelib to 0.6.0.
62 changes: 42 additions & 20 deletions src/pip/_internal/resolution/resolvelib/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Iterable,
Iterator,
List,
Mapping,
Optional,
Sequence,
Set,
Expand Down Expand Up @@ -104,6 +105,9 @@ def __init__(
self._installed_candidate_cache = (
{}
) # type: Dict[str, AlreadyInstalledCandidate]
self._extras_candidate_cache = (
{}
) # type: Dict[Tuple[int, FrozenSet[str]], ExtrasCandidate]

if not ignore_installed:
self._installed_dists = {
Expand All @@ -118,6 +122,16 @@ def force_reinstall(self):
# type: () -> bool
return self._force_reinstall

def _make_extras_candidate(self, base, extras):
# type: (BaseCandidate, FrozenSet[str]) -> ExtrasCandidate
cache_key = (id(base), extras)
try:
candidate = self._extras_candidate_cache[cache_key]
except KeyError:
candidate = ExtrasCandidate(base, extras)
self._extras_candidate_cache[cache_key] = candidate
return candidate

def _make_candidate_from_dist(
self,
dist, # type: Distribution
Expand All @@ -130,9 +144,9 @@ def _make_candidate_from_dist(
except KeyError:
base = AlreadyInstalledCandidate(dist, template, factory=self)
self._installed_candidate_cache[dist.key] = base
if extras:
return ExtrasCandidate(base, extras)
return base
if not extras:
return base
return self._make_extras_candidate(base, extras)

def _make_candidate_from_link(
self,
Expand Down Expand Up @@ -182,18 +196,18 @@ def _make_candidate_from_link(
return None
base = self._link_candidate_cache[link]

if extras:
return ExtrasCandidate(base, extras)
return base
if not extras:
return base
return self._make_extras_candidate(base, extras)

def _iter_found_candidates(
self,
ireqs, # type: Sequence[InstallRequirement]
specifier, # type: SpecifierSet
hashes, # type: Hashes
prefers_installed, # type: bool
):
# type: (...) -> Iterable[Candidate]
ireqs: Sequence[InstallRequirement],
specifier: SpecifierSet,
hashes: Hashes,
prefers_installed: bool,
incompatible_ids: Set[int],
) -> Iterable[Candidate]:
if not ireqs:
return ()

Expand Down Expand Up @@ -257,20 +271,27 @@ def iter_index_candidate_infos():
iter_index_candidate_infos,
installed_candidate,
prefers_installed,
incompatible_ids,
)

def find_candidates(
self,
requirements, # type: Sequence[Requirement]
constraint, # type: Constraint
prefers_installed, # type: bool
):
# type: (...) -> Iterable[Candidate]
identifier: str,
requirements: Mapping[str, Iterator[Requirement]],
incompatibilities: Mapping[str, Iterator[Candidate]],
constraint: Constraint,
prefers_installed: bool,
) -> Iterable[Candidate]:

# Since we cache all the candidates, incompatibility identification
# can be made quicker by comparing only the id() values.
incompat_ids = {id(c) for c in incompatibilities.get(identifier, ())}

explicit_candidates = set() # type: Set[Candidate]
ireqs = [] # type: List[InstallRequirement]
for req in requirements:
for req in requirements[identifier]:
cand, ireq = req.get_candidate_lookup()
if cand is not None:
if cand is not None and id(cand) not in incompat_ids:
explicit_candidates.add(cand)
if ireq is not None:
ireqs.append(ireq)
Expand All @@ -283,13 +304,14 @@ def find_candidates(
constraint.specifier,
constraint.hashes,
prefers_installed,
incompat_ids,
)

return (
c
for c in explicit_candidates
if constraint.is_satisfied_by(c)
and all(req.is_satisfied_by(c) for req in requirements)
and all(req.is_satisfied_by(c) for req in requirements[identifier])
)

def make_requirement_from_install_req(self, ireq, requested_extras):
Expand Down
18 changes: 11 additions & 7 deletions src/pip/_internal/resolution/resolvelib/found_candidates.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,15 @@ class FoundCandidates(collections_abc.Sequence):

def __init__(
self,
get_infos, # type: Callable[[], Iterator[IndexCandidateInfo]]
installed, # type: Optional[Candidate]
prefers_installed, # type: bool
get_infos: Callable[[], Iterator[IndexCandidateInfo]],
installed: Optional[Candidate],
prefers_installed: bool,
incompatible_ids: Set[int],
):
self._get_infos = get_infos
self._installed = installed
self._prefers_installed = prefers_installed
self._incompatible_ids = incompatible_ids

def __getitem__(self, index):
# type: (int) -> Candidate
Expand All @@ -119,10 +121,12 @@ def __iter__(self):
# type: () -> Iterator[Candidate]
infos = self._get_infos()
if not self._installed:
return _iter_built(infos)
if self._prefers_installed:
return _iter_built_with_prepended(self._installed, infos)
return _iter_built_with_inserted(self._installed, infos)
iterator = _iter_built(infos)
elif self._prefers_installed:
iterator = _iter_built_with_prepended(self._installed, infos)
else:
iterator = _iter_built_with_inserted(self._installed, infos)
return (c for c in iterator if id(c) not in self._incompatible_ids)

def __len__(self):
# type: () -> int
Expand Down
31 changes: 21 additions & 10 deletions src/pip/_internal/resolution/resolvelib/provider.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
from typing import TYPE_CHECKING, Dict, Iterable, Optional, Sequence, Union
from typing import (
TYPE_CHECKING,
Dict,
Iterable,
Iterator,
Mapping,
Optional,
Sequence,
Union,
)

from pip._vendor.resolvelib.providers import AbstractProvider

Expand Down Expand Up @@ -134,12 +143,12 @@ def _get_restrictive_rating(requirements):

return (delay_this, restrictive, order, key)

def find_matches(self, requirements):
# type: (Sequence[Requirement]) -> Iterable[Candidate]
if not requirements:
return []
name = requirements[0].project_name

def find_matches(
self,
identifier: str,
requirements: Mapping[str, Iterator[Requirement]],
incompatibilities: Mapping[str, Iterator[Candidate]],
) -> Iterable[Candidate]:
def _eligible_for_upgrade(name):
# type: (str) -> bool
"""Are upgrades allowed for this project?
Expand All @@ -159,9 +168,11 @@ def _eligible_for_upgrade(name):
return False

return self._factory.find_candidates(
requirements,
constraint=self._constraints.get(name, Constraint.empty()),
prefers_installed=(not _eligible_for_upgrade(name)),
identifier=identifier,
requirements=requirements,
constraint=self._constraints.get(identifier, Constraint.empty()),
prefers_installed=(not _eligible_for_upgrade(identifier)),
incompatibilities=incompatibilities,
)

def is_satisfied_by(self, requirement, candidate):
Expand Down
2 changes: 1 addition & 1 deletion src/pip/_vendor/resolvelib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"ResolutionTooDeep",
]

__version__ = "0.5.5"
__version__ = "0.6.0"


from .providers import AbstractProvider, AbstractResolver
Expand Down
6 changes: 3 additions & 3 deletions src/pip/_vendor/resolvelib/compat/collections_abc.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__all__ = ["Sequence"]
__all__ = ["Mapping", "Sequence"]

try:
from collections.abc import Sequence
from collections.abc import Mapping, Sequence
except ImportError:
from collections import Sequence
from collections import Mapping, Sequence
18 changes: 12 additions & 6 deletions src/pip/_vendor/resolvelib/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,18 @@ def get_preference(self, resolution, candidates, information):
"""
raise NotImplementedError

def find_matches(self, requirements):
"""Find all possible candidates that satisfy the given requirements.
def find_matches(self, identifier, requirements, incompatibilities):
"""Find all possible candidates that satisfy given constraints.

:param identifier: An identifier as returned by ``identify()``. This
identifies the dependency matches of which should be returned.
:param requirements: A mapping of requirements that all returned
candidates must satisfy. Each key is an identifier, and the value
an iterator of requirements for that dependency.
:param incompatibilities: A mapping of known incompatibilities of
each dependency. Each key is an identifier, and the value an
iterator of incompatibilities known to the resolver. All
incompatibilities *must* be excluded from the return value.

This should try to get candidates based on the requirements' types.
For VCS, local, and archive requirements, the one-and-only match is
Expand All @@ -66,10 +76,6 @@ def find_matches(self, requirements):
* An collection of candidates.
* An iterable of candidates. This will be consumed immediately into a
list of candidates.

:param requirements: A collection of requirements which all of the
returned candidates must match. All requirements are guaranteed to
have the same identifier. The collection is never empty.
"""
raise NotImplementedError

Expand Down
9 changes: 7 additions & 2 deletions src/pip/_vendor/resolvelib/providers.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ from typing import (
Collection,
Generic,
Iterable,
Iterator,
Mapping,
Optional,
Protocol,
Sequence,
Union,
)

Expand All @@ -31,7 +31,12 @@ class AbstractProvider(Generic[RT, CT, KT]):
candidates: IterableView[CT],
information: Collection[RequirementInformation[RT, CT]],
) -> Preference: ...
def find_matches(self, requirements: Sequence[RT]) -> Matches: ...
def find_matches(
self,
identifier: KT,
requirements: Mapping[KT, Iterator[RT]],
incompatibilities: Mapping[KT, Iterator[CT]],
) -> Matches: ...
def is_satisfied_by(self, requirement: RT, candidate: CT) -> bool: ...
def get_dependencies(self, candidate: CT) -> Iterable[RT]: ...

Expand Down
Loading