requirements.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. from pip._vendor.packaging.utils import canonicalize_name
  2. from pip._internal.utils.typing import MYPY_CHECK_RUNNING
  3. from .base import Requirement, format_name
  4. if MYPY_CHECK_RUNNING:
  5. from pip._vendor.packaging.specifiers import SpecifierSet
  6. from pip._internal.req.req_install import InstallRequirement
  7. from .base import Candidate, CandidateLookup
  8. class ExplicitRequirement(Requirement):
  9. def __init__(self, candidate):
  10. # type: (Candidate) -> None
  11. self.candidate = candidate
  12. def __str__(self):
  13. # type: () -> str
  14. return str(self.candidate)
  15. def __repr__(self):
  16. # type: () -> str
  17. return "{class_name}({candidate!r})".format(
  18. class_name=self.__class__.__name__,
  19. candidate=self.candidate,
  20. )
  21. @property
  22. def project_name(self):
  23. # type: () -> str
  24. # No need to canonicalise - the candidate did this
  25. return self.candidate.project_name
  26. @property
  27. def name(self):
  28. # type: () -> str
  29. # No need to canonicalise - the candidate did this
  30. return self.candidate.name
  31. def format_for_error(self):
  32. # type: () -> str
  33. return self.candidate.format_for_error()
  34. def get_candidate_lookup(self):
  35. # type: () -> CandidateLookup
  36. return self.candidate, None
  37. def is_satisfied_by(self, candidate):
  38. # type: (Candidate) -> bool
  39. return candidate == self.candidate
  40. class SpecifierRequirement(Requirement):
  41. def __init__(self, ireq):
  42. # type: (InstallRequirement) -> None
  43. assert ireq.link is None, "This is a link, not a specifier"
  44. self._ireq = ireq
  45. self._extras = frozenset(ireq.extras)
  46. def __str__(self):
  47. # type: () -> str
  48. return str(self._ireq.req)
  49. def __repr__(self):
  50. # type: () -> str
  51. return "{class_name}({requirement!r})".format(
  52. class_name=self.__class__.__name__,
  53. requirement=str(self._ireq.req),
  54. )
  55. @property
  56. def project_name(self):
  57. # type: () -> str
  58. return canonicalize_name(self._ireq.req.name)
  59. @property
  60. def name(self):
  61. # type: () -> str
  62. return format_name(self.project_name, self._extras)
  63. def format_for_error(self):
  64. # type: () -> str
  65. # Convert comma-separated specifiers into "A, B, ..., F and G"
  66. # This makes the specifier a bit more "human readable", without
  67. # risking a change in meaning. (Hopefully! Not all edge cases have
  68. # been checked)
  69. parts = [s.strip() for s in str(self).split(",")]
  70. if len(parts) == 0:
  71. return ""
  72. elif len(parts) == 1:
  73. return parts[0]
  74. return ", ".join(parts[:-1]) + " and " + parts[-1]
  75. def get_candidate_lookup(self):
  76. # type: () -> CandidateLookup
  77. return None, self._ireq
  78. def is_satisfied_by(self, candidate):
  79. # type: (Candidate) -> bool
  80. assert candidate.name == self.name, \
  81. "Internal issue: Candidate is not for this requirement " \
  82. " {} vs {}".format(candidate.name, self.name)
  83. # We can safely always allow prereleases here since PackageFinder
  84. # already implements the prerelease logic, and would have filtered out
  85. # prerelease candidates if the user does not expect them.
  86. spec = self._ireq.req.specifier
  87. return spec.contains(candidate.version, prereleases=True)
  88. class RequiresPythonRequirement(Requirement):
  89. """A requirement representing Requires-Python metadata.
  90. """
  91. def __init__(self, specifier, match):
  92. # type: (SpecifierSet, Candidate) -> None
  93. self.specifier = specifier
  94. self._candidate = match
  95. def __str__(self):
  96. # type: () -> str
  97. return "Python {}".format(self.specifier)
  98. def __repr__(self):
  99. # type: () -> str
  100. return "{class_name}({specifier!r})".format(
  101. class_name=self.__class__.__name__,
  102. specifier=str(self.specifier),
  103. )
  104. @property
  105. def project_name(self):
  106. # type: () -> str
  107. return self._candidate.project_name
  108. @property
  109. def name(self):
  110. # type: () -> str
  111. return self._candidate.name
  112. def format_for_error(self):
  113. # type: () -> str
  114. return str(self)
  115. def get_candidate_lookup(self):
  116. # type: () -> CandidateLookup
  117. if self.specifier.contains(self._candidate.version, prereleases=True):
  118. return self._candidate, None
  119. return None, None
  120. def is_satisfied_by(self, candidate):
  121. # type: (Candidate) -> bool
  122. assert candidate.name == self._candidate.name, "Not Python candidate"
  123. # We can safely always allow prereleases here since PackageFinder
  124. # already implements the prerelease logic, and would have filtered out
  125. # prerelease candidates if the user does not expect them.
  126. return self.specifier.contains(candidate.version, prereleases=True)
  127. class UnsatisfiableRequirement(Requirement):
  128. """A requirement that cannot be satisfied.
  129. """
  130. def __init__(self, name):
  131. # type: (str) -> None
  132. self._name = name
  133. def __str__(self):
  134. # type: () -> str
  135. return "{} (unavailable)".format(self._name)
  136. def __repr__(self):
  137. # type: () -> str
  138. return "{class_name}({name!r})".format(
  139. class_name=self.__class__.__name__,
  140. name=str(self._name),
  141. )
  142. @property
  143. def project_name(self):
  144. # type: () -> str
  145. return self._name
  146. @property
  147. def name(self):
  148. # type: () -> str
  149. return self._name
  150. def format_for_error(self):
  151. # type: () -> str
  152. return str(self)
  153. def get_candidate_lookup(self):
  154. # type: () -> CandidateLookup
  155. return None, None
  156. def is_satisfied_by(self, candidate):
  157. # type: (Candidate) -> bool
  158. return False