Skip to content

Commit db601c6

Browse files
avoid special-casing the python version requirement in download.py
1 parent 64fc3f3 commit db601c6

File tree

5 files changed

+34
-18
lines changed

5 files changed

+34
-18
lines changed

src/pip/_internal/commands/download.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,12 @@ def as_json(self) -> Dict[str, Any]:
8181

8282
@dataclass
8383
class DownloadInfos:
84-
# python_version: Optional[Requirement] = None
85-
python_version: Optional[str] = None
84+
implicit_requirements: List[Requirement] = field(default_factory=list)
8685
resolution: Dict[str, RequirementDownloadInfo] = field(default_factory=dict)
8786

8887
def as_json(self) -> Dict[str, Any]:
8988
return {
90-
"python_version": self.python_version and str(self.python_version),
89+
"implicit_requirements": [str(req) for req in self.implicit_requirements],
9190
"resolution": {
9291
name: info.as_json() for name, info in self.resolution.items()
9392
},
@@ -241,8 +240,9 @@ def run(self, options: Values, args: List[str]) -> int:
241240
for candidate in requirement_set.candidates.mapping.values():
242241
# This will occur for the python version requirement, for example.
243242
if candidate.name not in requirement_set.requirements:
244-
# download_infos.python_version = candidate.as_requirement()
245-
download_infos.python_version = str(candidate)
243+
download_infos.implicit_requirements.append(
244+
candidate.as_serializable_requirement()
245+
)
246246
continue
247247
req = requirement_set.requirements[candidate.name]
248248
assert req.name is not None
@@ -251,7 +251,7 @@ def run(self, options: Values, args: List[str]) -> int:
251251
download_infos.resolution[
252252
req.name
253253
] = RequirementDownloadInfo.from_req_and_link(
254-
req=candidate.as_requirement(),
254+
req=candidate.as_serializable_requirement(),
255255
link=req.link,
256256
)
257257

src/pip/_internal/metadata/base.py

+3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ def __repr__(self) -> str:
101101
def __str__(self) -> str:
102102
return f"{self.raw_name} {self.version}"
103103

104+
def as_serializable_requirement(self) -> Requirement:
105+
raise NotImplementedError()
106+
104107
@property
105108
def location(self) -> Optional[str]:
106109
"""Where the distribution is loaded from.

src/pip/_internal/metadata/pkg_resources.py

+3
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ def from_wheel(cls, wheel: Wheel, name: str) -> "Distribution":
120120
)
121121
return cls(dist)
122122

123+
def as_serializable_requirement(self) -> Requirement:
124+
return self._dist.as_requirement()
125+
123126
@property
124127
def location(self) -> Optional[str]:
125128
return self._dist.location

src/pip/_internal/resolution/resolvelib/base.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -61,34 +61,34 @@ def is_satisfied_by(self, candidate: "Candidate") -> bool:
6161
return self.specifier.contains(candidate.version, prereleases=True)
6262

6363

64-
class Requirement:
65-
@property
64+
class Requirement(metaclass=abc.ABCMeta):
65+
@abc.abstractproperty
6666
def project_name(self) -> NormalizedName:
6767
"""The "project name" of a requirement.
6868
6969
This is different from ``name`` if this requirement contains extras,
7070
in which case ``name`` would contain the ``[...]`` part, while this
7171
refers to the name of the project.
7272
"""
73-
raise NotImplementedError("Subclass should override")
7473

75-
@property
74+
@abc.abstractproperty
7675
def name(self) -> str:
7776
"""The name identifying this requirement in the resolver.
7877
7978
This is different from ``project_name`` if this requirement contains
8079
extras, where ``project_name`` would not contain the ``[...]`` part.
8180
"""
82-
raise NotImplementedError("Subclass should override")
8381

8482
def is_satisfied_by(self, candidate: "Candidate") -> bool:
8583
return False
8684

85+
@abc.abstractmethod
8786
def get_candidate_lookup(self) -> CandidateLookup:
88-
raise NotImplementedError("Subclass should override")
87+
...
8988

89+
@abc.abstractmethod
9090
def format_for_error(self) -> str:
91-
raise NotImplementedError("Subclass should override")
91+
...
9292

9393

9494
def _match_link(link: Link, candidate: "Candidate") -> bool:
@@ -120,7 +120,7 @@ def version(self) -> CandidateVersion:
120120
...
121121

122122
@abc.abstractmethod
123-
def as_requirement(self) -> PkgRequirement:
123+
def as_serializable_requirement(self) -> PkgRequirement:
124124
...
125125

126126
@abc.abstractproperty

src/pip/_internal/resolution/resolvelib/candidates.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535

3636
# Avoid conflicting with the PyPI package "Python".
3737
REQUIRES_PYTHON_IDENTIFIER = cast(NormalizedName, "<Python from Requires-Python>")
38+
# Avoid clashing with any package on PyPI, but remain parseable as a Requirement. This
39+
# should only be used for .as_serializable_requirement().
40+
REQUIRES_PYTHON_SERIALIZABLE_IDENTIFIER = cast(NormalizedName, "Requires-Python")
3841

3942

4043
def as_base_candidate(candidate: Candidate) -> Optional[BaseCandidate]:
@@ -160,7 +163,7 @@ def __init__(
160163
def __str__(self) -> str:
161164
return f"{self.name} {self.version}"
162165

163-
def as_requirement(self) -> PkgRequirement:
166+
def as_serializable_requirement(self) -> PkgRequirement:
164167
return produce_exact_version_requirement(self.name, str(self.version))
165168

166169
def __repr__(self) -> str:
@@ -371,6 +374,9 @@ def name(self) -> str:
371374
def version(self) -> CandidateVersion:
372375
return self.dist.version
373376

377+
def as_serializable_requirement(self) -> PkgRequirement:
378+
return self.dist.as_serializable_requirement()
379+
374380
@property
375381
def is_editable(self) -> bool:
376382
return self.dist.editable
@@ -453,6 +459,9 @@ def name(self) -> str:
453459
def version(self) -> CandidateVersion:
454460
return self.base.version
455461

462+
def as_serializable_requirement(self) -> PkgRequirement:
463+
return self.base.as_serializable_requirement()
464+
456465
def format_for_error(self) -> str:
457466
return "{} [{}]".format(
458467
self.base.format_for_error(), ", ".join(sorted(self.extras))
@@ -535,9 +544,10 @@ def name(self) -> str:
535544
def version(self) -> CandidateVersion:
536545
return self._version
537546

538-
def as_requirement(self) -> PkgRequirement:
539-
raise NotImplementedError("FIXME!!!")
540-
# return produce_exact_version_requirement(self.name, str(self.version))
547+
def as_serializable_requirement(self) -> PkgRequirement:
548+
return produce_exact_version_requirement(
549+
REQUIRES_PYTHON_SERIALIZABLE_IDENTIFIER, str(self.version)
550+
)
541551

542552
@property
543553
def is_editable(self) -> bool:

0 commit comments

Comments
 (0)