Spaces:
Running
Running
face-swap-docker1
/
mynewshinyroop
/Lib
/site-packages
/pip
/_internal
/resolution
/resolvelib
/provider.py
import collections | |
import math | |
from typing import ( | |
TYPE_CHECKING, | |
Dict, | |
Iterable, | |
Iterator, | |
Mapping, | |
Sequence, | |
TypeVar, | |
Union, | |
) | |
from pip._vendor.resolvelib.providers import AbstractProvider | |
from .base import Candidate, Constraint, Requirement | |
from .candidates import REQUIRES_PYTHON_IDENTIFIER | |
from .factory import Factory | |
if TYPE_CHECKING: | |
from pip._vendor.resolvelib.providers import Preference | |
from pip._vendor.resolvelib.resolvers import RequirementInformation | |
PreferenceInformation = RequirementInformation[Requirement, Candidate] | |
_ProviderBase = AbstractProvider[Requirement, Candidate, str] | |
else: | |
_ProviderBase = AbstractProvider | |
# Notes on the relationship between the provider, the factory, and the | |
# candidate and requirement classes. | |
# | |
# The provider is a direct implementation of the resolvelib class. Its role | |
# is to deliver the API that resolvelib expects. | |
# | |
# Rather than work with completely abstract "requirement" and "candidate" | |
# concepts as resolvelib does, pip has concrete classes implementing these two | |
# ideas. The API of Requirement and Candidate objects are defined in the base | |
# classes, but essentially map fairly directly to the equivalent provider | |
# methods. In particular, `find_matches` and `is_satisfied_by` are | |
# requirement methods, and `get_dependencies` is a candidate method. | |
# | |
# The factory is the interface to pip's internal mechanisms. It is stateless, | |
# and is created by the resolver and held as a property of the provider. It is | |
# responsible for creating Requirement and Candidate objects, and provides | |
# services to those objects (access to pip's finder and preparer). | |
D = TypeVar("D") | |
V = TypeVar("V") | |
def _get_with_identifier( | |
mapping: Mapping[str, V], | |
identifier: str, | |
default: D, | |
) -> Union[D, V]: | |
"""Get item from a package name lookup mapping with a resolver identifier. | |
This extra logic is needed when the target mapping is keyed by package | |
name, which cannot be directly looked up with an identifier (which may | |
contain requested extras). Additional logic is added to also look up a value | |
by "cleaning up" the extras from the identifier. | |
""" | |
if identifier in mapping: | |
return mapping[identifier] | |
# HACK: Theoretically we should check whether this identifier is a valid | |
# "NAME[EXTRAS]" format, and parse out the name part with packaging or | |
# some regular expression. But since pip's resolver only spits out three | |
# kinds of identifiers: normalized PEP 503 names, normalized names plus | |
# extras, and Requires-Python, we can cheat a bit here. | |
name, open_bracket, _ = identifier.partition("[") | |
if open_bracket and name in mapping: | |
return mapping[name] | |
return default | |
class PipProvider(_ProviderBase): | |
"""Pip's provider implementation for resolvelib. | |
:params constraints: A mapping of constraints specified by the user. Keys | |
are canonicalized project names. | |
:params ignore_dependencies: Whether the user specified ``--no-deps``. | |
:params upgrade_strategy: The user-specified upgrade strategy. | |
:params user_requested: A set of canonicalized package names that the user | |
supplied for pip to install/upgrade. | |
""" | |
def __init__( | |
self, | |
factory: Factory, | |
constraints: Dict[str, Constraint], | |
ignore_dependencies: bool, | |
upgrade_strategy: str, | |
user_requested: Dict[str, int], | |
) -> None: | |
self._factory = factory | |
self._constraints = constraints | |
self._ignore_dependencies = ignore_dependencies | |
self._upgrade_strategy = upgrade_strategy | |
self._user_requested = user_requested | |
self._known_depths: Dict[str, float] = collections.defaultdict(lambda: math.inf) | |
def identify(self, requirement_or_candidate: Union[Requirement, Candidate]) -> str: | |
return requirement_or_candidate.name | |
def get_preference( | |
self, | |
identifier: str, | |
resolutions: Mapping[str, Candidate], | |
candidates: Mapping[str, Iterator[Candidate]], | |
information: Mapping[str, Iterable["PreferenceInformation"]], | |
backtrack_causes: Sequence["PreferenceInformation"], | |
) -> "Preference": | |
"""Produce a sort key for given requirement based on preference. | |
The lower the return value is, the more preferred this group of | |
arguments is. | |
Currently pip considers the following in order: | |
* Prefer if any of the known requirements is "direct", e.g. points to an | |
explicit URL. | |
* If equal, prefer if any requirement is "pinned", i.e. contains | |
operator ``===`` or ``==``. | |
* If equal, calculate an approximate "depth" and resolve requirements | |
closer to the user-specified requirements first. If the depth cannot | |
by determined (eg: due to no matching parents), it is considered | |
infinite. | |
* Order user-specified requirements by the order they are specified. | |
* If equal, prefers "non-free" requirements, i.e. contains at least one | |
operator, such as ``>=`` or ``<``. | |
* If equal, order alphabetically for consistency (helps debuggability). | |
""" | |
try: | |
next(iter(information[identifier])) | |
except StopIteration: | |
# There is no information for this identifier, so there's no known | |
# candidates. | |
has_information = False | |
else: | |
has_information = True | |
if has_information: | |
lookups = (r.get_candidate_lookup() for r, _ in information[identifier]) | |
candidate, ireqs = zip(*lookups) | |
else: | |
candidate, ireqs = None, () | |
operators = [ | |
specifier.operator | |
for specifier_set in (ireq.specifier for ireq in ireqs if ireq) | |
for specifier in specifier_set | |
] | |
direct = candidate is not None | |
pinned = any(op[:2] == "==" for op in operators) | |
unfree = bool(operators) | |
try: | |
requested_order: Union[int, float] = self._user_requested[identifier] | |
except KeyError: | |
requested_order = math.inf | |
if has_information: | |
parent_depths = ( | |
self._known_depths[parent.name] if parent is not None else 0.0 | |
for _, parent in information[identifier] | |
) | |
inferred_depth = min(d for d in parent_depths) + 1.0 | |
else: | |
inferred_depth = math.inf | |
else: | |
inferred_depth = 1.0 | |
self._known_depths[identifier] = inferred_depth | |
requested_order = self._user_requested.get(identifier, math.inf) | |
# Requires-Python has only one candidate and the check is basically | |
# free, so we always do it first to avoid needless work if it fails. | |
requires_python = identifier == REQUIRES_PYTHON_IDENTIFIER | |
# Prefer the causes of backtracking on the assumption that the problem | |
# resolving the dependency tree is related to the failures that caused | |
# the backtracking | |
backtrack_cause = self.is_backtrack_cause(identifier, backtrack_causes) | |
return ( | |
not requires_python, | |
not direct, | |
not pinned, | |
not backtrack_cause, | |
inferred_depth, | |
requested_order, | |
not unfree, | |
identifier, | |
) | |
def find_matches( | |
self, | |
identifier: str, | |
requirements: Mapping[str, Iterator[Requirement]], | |
incompatibilities: Mapping[str, Iterator[Candidate]], | |
) -> Iterable[Candidate]: | |
def _eligible_for_upgrade(identifier: str) -> bool: | |
"""Are upgrades allowed for this project? | |
This checks the upgrade strategy, and whether the project was one | |
that the user specified in the command line, in order to decide | |
whether we should upgrade if there's a newer version available. | |
(Note that we don't need access to the `--upgrade` flag, because | |
an upgrade strategy of "to-satisfy-only" means that `--upgrade` | |
was not specified). | |
""" | |
if self._upgrade_strategy == "eager": | |
return True | |
elif self._upgrade_strategy == "only-if-needed": | |
user_order = _get_with_identifier( | |
self._user_requested, | |
identifier, | |
default=None, | |
) | |
return user_order is not None | |
return False | |
constraint = _get_with_identifier( | |
self._constraints, | |
identifier, | |
default=Constraint.empty(), | |
) | |
return self._factory.find_candidates( | |
identifier=identifier, | |
requirements=requirements, | |
constraint=constraint, | |
prefers_installed=(not _eligible_for_upgrade(identifier)), | |
incompatibilities=incompatibilities, | |
) | |
def is_satisfied_by(self, requirement: Requirement, candidate: Candidate) -> bool: | |
return requirement.is_satisfied_by(candidate) | |
def get_dependencies(self, candidate: Candidate) -> Sequence[Requirement]: | |
with_requires = not self._ignore_dependencies | |
return [r for r in candidate.iter_dependencies(with_requires) if r is not None] | |
def is_backtrack_cause( | |
identifier: str, backtrack_causes: Sequence["PreferenceInformation"] | |
) -> bool: | |
for backtrack_cause in backtrack_causes: | |
if identifier == backtrack_cause.requirement.name: | |
return True | |
if backtrack_cause.parent and identifier == backtrack_cause.parent.name: | |
return True | |
return False | |