lyrics-classifier
/
venv
/lib
/python3.8
/site-packages
/pip
/_internal
/resolution
/resolvelib
/provider.py
from pip._vendor.packaging.specifiers import SpecifierSet | |
from pip._vendor.resolvelib.providers import AbstractProvider | |
from pip._internal.utils.typing import MYPY_CHECK_RUNNING | |
if MYPY_CHECK_RUNNING: | |
from typing import ( | |
Any, | |
Dict, | |
Iterable, | |
Optional, | |
Sequence, | |
Set, | |
Tuple, | |
Union, | |
) | |
from .base import Requirement, Candidate | |
from .factory import Factory | |
# 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). | |
class PipProvider(AbstractProvider): | |
def __init__( | |
self, | |
factory, # type: Factory | |
constraints, # type: Dict[str, SpecifierSet] | |
ignore_dependencies, # type: bool | |
upgrade_strategy, # type: str | |
user_requested, # type: Set[str] | |
): | |
# type: (...) -> None | |
self._factory = factory | |
self._constraints = constraints | |
self._ignore_dependencies = ignore_dependencies | |
self._upgrade_strategy = upgrade_strategy | |
self.user_requested = user_requested | |
def _sort_matches(self, matches): | |
# type: (Iterable[Candidate]) -> Sequence[Candidate] | |
# The requirement is responsible for returning a sequence of potential | |
# candidates, one per version. The provider handles the logic of | |
# deciding the order in which these candidates should be passed to | |
# the resolver. | |
# The `matches` argument is a sequence of candidates, one per version, | |
# which are potential options to be installed. The requirement will | |
# have already sorted out whether to give us an already-installed | |
# candidate or a version from PyPI (i.e., it will deal with options | |
# like --force-reinstall and --ignore-installed). | |
# We now work out the correct order. | |
# | |
# 1. If no other considerations apply, later versions take priority. | |
# 2. An already installed distribution is preferred over any other, | |
# unless the user has requested an upgrade. | |
# Upgrades are allowed when: | |
# * The --upgrade flag is set, and | |
# - The project was specified on the command line, or | |
# - The project is a dependency and the "eager" upgrade strategy | |
# was requested. | |
def _eligible_for_upgrade(name): | |
# type: (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": | |
return (name in self.user_requested) | |
return False | |
def sort_key(c): | |
# type: (Candidate) -> int | |
"""Return a sort key for the matches. | |
The highest priority should be given to installed candidates that | |
are not eligible for upgrade. We use the integer value in the first | |
part of the key to sort these before other candidates. | |
We only pull the installed candidate to the bottom (i.e. most | |
preferred), but otherwise keep the ordering returned by the | |
requirement. The requirement is responsible for returning a list | |
otherwise sorted for the resolver, taking account for versions | |
and binary preferences as specified by the user. | |
""" | |
if c.is_installed and not _eligible_for_upgrade(c.name): | |
return 1 | |
return 0 | |
return sorted(matches, key=sort_key) | |
def identify(self, dependency): | |
# type: (Union[Requirement, Candidate]) -> str | |
return dependency.name | |
def get_preference( | |
self, | |
resolution, # type: Optional[Candidate] | |
candidates, # type: Sequence[Candidate] | |
information # type: Sequence[Tuple[Requirement, Candidate]] | |
): | |
# type: (...) -> Any | |
# Use the "usual" value for now | |
return len(candidates) | |
def find_matches(self, requirements): | |
# type: (Sequence[Requirement]) -> Iterable[Candidate] | |
if not requirements: | |
return [] | |
constraint = self._constraints.get( | |
requirements[0].name, SpecifierSet(), | |
) | |
candidates = self._factory.find_candidates(requirements, constraint) | |
return reversed(self._sort_matches(candidates)) | |
def is_satisfied_by(self, requirement, candidate): | |
# type: (Requirement, Candidate) -> bool | |
return requirement.is_satisfied_by(candidate) | |
def get_dependencies(self, candidate): | |
# type: (Candidate) -> Sequence[Requirement] | |
with_requires = not self._ignore_dependencies | |
return [ | |
r | |
for r in candidate.iter_dependencies(with_requires) | |
if r is not None | |
] | |