Mini Shell
from typing import Any, Optional
from pip._vendor.packaging.specifiers import SpecifierSet
from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
from pip._internal.req.constructors import install_req_drop_extras
from pip._internal.req.req_install import InstallRequirement
from .base import Candidate, CandidateLookup, Requirement, format_name
class ExplicitRequirement(Requirement):
def __init__(self, candidate: Candidate) -> None:
self.candidate = candidate
def __str__(self) -> str:
return str(self.candidate)
def __repr__(self) -> str:
return f"{self.__class__.__name__}({self.candidate!r})"
def __hash__(self) -> int:
return hash(self.candidate)
def __eq__(self, other: Any) -> bool:
if not isinstance(other, ExplicitRequirement):
return False
return self.candidate == other.candidate
@property
def project_name(self) -> NormalizedName:
# No need to canonicalize - the candidate did this
return self.candidate.project_name
@property
def name(self) -> str:
# No need to canonicalize - the candidate did this
return self.candidate.name
def format_for_error(self) -> str:
return self.candidate.format_for_error()
def get_candidate_lookup(self) -> CandidateLookup:
return self.candidate, None
def is_satisfied_by(self, candidate: Candidate) -> bool:
return candidate == self.candidate
class SpecifierRequirement(Requirement):
def __init__(self, ireq: InstallRequirement) -> None:
assert ireq.link is None, "This is a link, not a specifier"
self._ireq = ireq
self._equal_cache: Optional[str] = None
self._hash: Optional[int] = None
self._extras = frozenset(canonicalize_name(e) for e in self._ireq.extras)
@property
def _equal(self) -> str:
if self._equal_cache is not None:
return self._equal_cache
self._equal_cache = str(self._ireq)
return self._equal_cache
def __str__(self) -> str:
return str(self._ireq.req)
def __repr__(self) -> str:
return f"{self.__class__.__name__}({str(self._ireq.req)!r})"
def __eq__(self, other: object) -> bool:
if not isinstance(other, SpecifierRequirement):
return NotImplemented
return self._equal == other._equal
def __hash__(self) -> int:
if self._hash is not None:
return self._hash
self._hash = hash(self._equal)
return self._hash
@property
def project_name(self) -> NormalizedName:
assert self._ireq.req, "Specifier-backed ireq is always PEP 508"
return canonicalize_name(self._ireq.req.name)
@property
def name(self) -> str:
return format_name(self.project_name, self._extras)
def format_for_error(self) -> 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) -> CandidateLookup:
return None, self._ireq
def is_satisfied_by(self, candidate: Candidate) -> bool:
assert candidate.name == self.name, (
f"Internal issue: Candidate is not for this requirement "
f"{candidate.name} vs {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.
assert self._ireq.req, "Specifier-backed ireq is always PEP 508"
spec = self._ireq.req.specifier
return spec.contains(candidate.version, prereleases=True)
class SpecifierWithoutExtrasRequirement(SpecifierRequirement):
"""
Requirement backed by an install requirement on a base package.
Trims extras from its install requirement if there are any.
"""
def __init__(self, ireq: InstallRequirement) -> None:
assert ireq.link is None, "This is a link, not a specifier"
self._ireq = install_req_drop_extras(ireq)
self._equal_cache: Optional[str] = None
self._hash: Optional[int] = None
self._extras = frozenset(canonicalize_name(e) for e in self._ireq.extras)
@property
def _equal(self) -> str:
if self._equal_cache is not None:
return self._equal_cache
self._equal_cache = str(self._ireq)
return self._equal_cache
def __eq__(self, other: object) -> bool:
if not isinstance(other, SpecifierWithoutExtrasRequirement):
return NotImplemented
return self._equal == other._equal
def __hash__(self) -> int:
if self._hash is not None:
return self._hash
self._hash = hash(self._equal)
return self._hash
class RequiresPythonRequirement(Requirement):
"""A requirement representing Requires-Python metadata."""
def __init__(self, specifier: SpecifierSet, match: Candidate) -> None:
self.specifier = specifier
self._specifier_string = str(specifier) # for faster __eq__
self._hash: Optional[int] = None
self._candidate = match
def __str__(self) -> str:
return f"Python {self.specifier}"
def __repr__(self) -> str:
return f"{self.__class__.__name__}({str(self.specifier)!r})"
def __hash__(self) -> int:
if self._hash is not None:
return self._hash
self._hash = hash((self._specifier_string, self._candidate))
return self._hash
def __eq__(self, other: Any) -> bool:
if not isinstance(other, RequiresPythonRequirement):
return False
return (
self._specifier_string == other._specifier_string
and self._candidate == other._candidate
)
@property
def project_name(self) -> NormalizedName:
return self._candidate.project_name
@property
def name(self) -> str:
return self._candidate.name
def format_for_error(self) -> str:
return str(self)
def get_candidate_lookup(self) -> CandidateLookup:
if self.specifier.contains(self._candidate.version, prereleases=True):
return self._candidate, None
return None, None
def is_satisfied_by(self, candidate: 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)
class UnsatisfiableRequirement(Requirement):
"""A requirement that cannot be satisfied."""
def __init__(self, name: NormalizedName) -> None:
self._name = name
def __str__(self) -> str:
return f"{self._name} (unavailable)"
def __repr__(self) -> str:
return f"{self.__class__.__name__}({str(self._name)!r})"
def __eq__(self, other: object) -> bool:
if not isinstance(other, UnsatisfiableRequirement):
return NotImplemented
return self._name == other._name
def __hash__(self) -> int:
return hash(self._name)
@property
def project_name(self) -> NormalizedName:
return self._name
@property
def name(self) -> str:
return self._name
def format_for_error(self) -> str:
return str(self)
def get_candidate_lookup(self) -> CandidateLookup:
return None, None
def is_satisfied_by(self, candidate: Candidate) -> bool:
return False
Zerion Mini Shell 1.0