| from pip._vendor.packaging.utils import canonicalize_name |
| |
| from pip._internal.utils.typing import MYPY_CHECK_RUNNING |
| |
| from .base import Requirement, format_name |
| |
| if MYPY_CHECK_RUNNING: |
| from pip._vendor.packaging.specifiers import SpecifierSet |
| |
| from pip._internal.req.req_install import InstallRequirement |
| |
| from .base import Candidate, CandidateLookup |
| |
| |
| class ExplicitRequirement(Requirement): |
| def __init__(self, candidate): |
| # type: (Candidate) -> None |
| self.candidate = candidate |
| |
| def __repr__(self): |
| # type: () -> str |
| return "{class_name}({candidate!r})".format( |
| class_name=self.__class__.__name__, |
| candidate=self.candidate, |
| ) |
| |
| @property |
| def name(self): |
| # type: () -> str |
| # No need to canonicalise - the candidate did this |
| return self.candidate.name |
| |
| def format_for_error(self): |
| # type: () -> str |
| return self.candidate.format_for_error() |
| |
| def get_candidate_lookup(self): |
| # type: () -> CandidateLookup |
| return self.candidate, None |
| |
| def is_satisfied_by(self, candidate): |
| # type: (Candidate) -> bool |
| return candidate == self.candidate |
| |
| |
| class SpecifierRequirement(Requirement): |
| def __init__(self, ireq): |
| # type: (InstallRequirement) -> None |
| assert ireq.link is None, "This is a link, not a specifier" |
| self._ireq = ireq |
| self._extras = frozenset(ireq.extras) |
| |
| def __str__(self): |
| # type: () -> str |
| return str(self._ireq.req) |
| |
| def __repr__(self): |
| # type: () -> str |
| return "{class_name}({requirement!r})".format( |
| class_name=self.__class__.__name__, |
| requirement=str(self._ireq.req), |
| ) |
| |
| @property |
| def name(self): |
| # type: () -> str |
| canonical_name = canonicalize_name(self._ireq.req.name) |
| return format_name(canonical_name, self._extras) |
| |
| def format_for_error(self): |
| # type: () -> str |
| |
| # Convert comma-separated specifiers into "A, B, ..., F and G" |
| # This makes the specifier a bit more "human readable", without |
| # risking a change in meaning. (Hopefully! Not all edge cases have |
| # been checked) |
| parts = [s.strip() for s in str(self).split(",")] |
| if len(parts) == 0: |
| return "" |
| elif len(parts) == 1: |
| return parts[0] |
| |
| return ", ".join(parts[:-1]) + " and " + parts[-1] |
| |
| def get_candidate_lookup(self): |
| # type: () -> CandidateLookup |
| return None, self._ireq |
| |
| def is_satisfied_by(self, candidate): |
| # type: (Candidate) -> bool |
| assert candidate.name == self.name, \ |
| "Internal issue: Candidate is not for this requirement " \ |
| " {} vs {}".format(candidate.name, self.name) |
| # We can safely always allow prereleases here since PackageFinder |
| # already implements the prerelease logic, and would have filtered out |
| # prerelease candidates if the user does not expect them. |
| spec = self._ireq.req.specifier |
| return spec.contains(candidate.version, prereleases=True) |
| |
| |
| class RequiresPythonRequirement(Requirement): |
| """A requirement representing Requires-Python metadata. |
| """ |
| def __init__(self, specifier, match): |
| # type: (SpecifierSet, Candidate) -> None |
| self.specifier = specifier |
| self._candidate = match |
| |
| def __repr__(self): |
| # type: () -> str |
| return "{class_name}({specifier!r})".format( |
| class_name=self.__class__.__name__, |
| specifier=str(self.specifier), |
| ) |
| |
| @property |
| def name(self): |
| # type: () -> str |
| return self._candidate.name |
| |
| def format_for_error(self): |
| # type: () -> str |
| return "Python " + str(self.specifier) |
| |
| def get_candidate_lookup(self): |
| # type: () -> CandidateLookup |
| if self.specifier.contains(self._candidate.version, prereleases=True): |
| return self._candidate, None |
| return None, None |
| |
| def is_satisfied_by(self, candidate): |
| # type: (Candidate) -> bool |
| assert candidate.name == self._candidate.name, "Not Python candidate" |
| # We can safely always allow prereleases here since PackageFinder |
| # already implements the prerelease logic, and would have filtered out |
| # prerelease candidates if the user does not expect them. |
| return self.specifier.contains(candidate.version, prereleases=True) |