| Viewing file:  requirements.py (7.88 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
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
 
 |