Skip to content

Commit 3b7c959

Browse files
authored
[WIP] Progressive work towards working pip again (#8)
* Minimal hack to make install work again * Add NotImplementedError to branches not handling variants right now * Disentangle variants from tags Remove the code responsible for handling variants via injecting them into tags. This is in preparation for a new logic that is going to handle variants more explicitly. * Remove unused `read_provider_priority_from_pip_config()` * Reimplement variant filtering and sorting directly * Fetch variants.json lazily * Support multiple variants.json files * Fix variant priorities * Add missing sys import * Let variantlib take care of plugin loading * Fix installing from local files * Remove stale PluginLoader import
1 parent 3292f9a commit 3b7c959

File tree

9 files changed

+99
-119
lines changed

9 files changed

+99
-119
lines changed

src/pip/_internal/cache.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ def get(
150150
package_name,
151151
)
152152
continue
153+
raise NotImplementedError
153154
if not wheel.supported(supported_tags):
154155
# Built for a different python/arch/etc
155156
continue

src/pip/_internal/index/package_finder.py

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import itertools
66
import logging
77
import re
8+
import sys
89
from dataclasses import dataclass
910
from typing import TYPE_CHECKING, FrozenSet, Iterable, List, Optional, Set, Tuple, Union
1011

@@ -36,7 +37,11 @@
3637
from pip._internal.utils.misc import build_netloc
3738
from pip._internal.utils.packaging import check_requires_python
3839
from pip._internal.utils.unpacking import SUPPORTED_EXTENSIONS
39-
from pip._internal.utils.variant import VariantJson
40+
from pip._internal.utils.variant import (
41+
VariantJson,
42+
get_cached_variant_hashes_by_priority,
43+
get_variants_json_filename,
44+
)
4045

4146
if TYPE_CHECKING:
4247
from pip._vendor.typing_extensions import TypeGuard
@@ -105,6 +110,7 @@ class LinkType(enum.Enum):
105110
format_invalid = enum.auto()
106111
platform_mismatch = enum.auto()
107112
requires_python_mismatch = enum.auto()
113+
variant_unsupported = enum.auto()
108114

109115

110116
class LinkEvaluator:
@@ -154,7 +160,7 @@ def __init__(
154160
self._target_python = target_python
155161

156162
self.project_name = project_name
157-
self.variants_json = None
163+
self.variants_json = {}
158164

159165
def evaluate_link(self, link: Link) -> Tuple[LinkType, str, Optional[str]]:
160166
"""
@@ -204,9 +210,7 @@ def evaluate_link(self, link: Link) -> Tuple[LinkType, str, Optional[str]]:
204210
return (LinkType.different_project, reason, None)
205211

206212
variant_hash = wheel.variant_hash
207-
supported_tags = self._target_python.get_unsorted_tags(
208-
variants_json=self.variants_json
209-
)
213+
supported_tags = self._target_python.get_unsorted_tags()
210214
if not wheel.supported(supported_tags):
211215
# Include the wheel's tags in the reason string to
212216
# simplify troubleshooting compatibility issues.
@@ -217,6 +221,20 @@ def evaluate_link(self, link: Link) -> Tuple[LinkType, str, Optional[str]]:
217221
)
218222
return (LinkType.platform_mismatch, reason, None)
219223

224+
supported_variants = set(
225+
get_cached_variant_hashes_by_priority(
226+
self.variants_json.get(
227+
get_variants_json_filename(wheel)
228+
)
229+
)
230+
)
231+
if wheel.variant_hash not in supported_variants:
232+
reason = (
233+
f"variant {wheel.variant_hash} is not compatible with "
234+
f"the system"
235+
)
236+
return (LinkType.variant_unsupported, reason, None)
237+
220238
version = wheel.version
221239

222240
# This should be up by the self.ok_binary check, but see issue 2700.
@@ -384,7 +402,7 @@ def create(
384402
allow_all_prereleases: bool = False,
385403
specifier: Optional[specifiers.BaseSpecifier] = None,
386404
hashes: Optional[Hashes] = None,
387-
variants_json: Optional[VariantJson] = None,
405+
variants_json: dict[VariantJson] = {},
388406
) -> "CandidateEvaluator":
389407
"""Create a CandidateEvaluator object.
390408
@@ -401,9 +419,7 @@ def create(
401419
if specifier is None:
402420
specifier = specifiers.SpecifierSet()
403421

404-
supported_tags = target_python.get_sorted_tags(
405-
variants_json=variants_json,
406-
)
422+
supported_tags = target_python.get_sorted_tags()
407423

408424
return cls(
409425
project_name=project_name,
@@ -412,6 +428,7 @@ def create(
412428
prefer_binary=prefer_binary,
413429
allow_all_prereleases=allow_all_prereleases,
414430
hashes=hashes,
431+
variants_json=variants_json,
415432
)
416433

417434
def __init__(
@@ -422,6 +439,7 @@ def __init__(
422439
prefer_binary: bool = False,
423440
allow_all_prereleases: bool = False,
424441
hashes: Optional[Hashes] = None,
442+
variants_json: dict[VariantJson] = [],
425443
) -> None:
426444
"""
427445
:param supported_tags: The PEP 425 tags supported by the target
@@ -433,6 +451,7 @@ def __init__(
433451
self._project_name = project_name
434452
self._specifier = specifier
435453
self._supported_tags = supported_tags
454+
self._variants_json = variants_json
436455
# Since the index of the tag in the _supported_tags list is used
437456
# as a priority, precompute a map from tag to index/priority to be
438457
# used in wheel.find_most_preferred_tag.
@@ -513,12 +532,20 @@ def _sort_key(self, candidate: InstallationCandidate) -> CandidateSortingKey:
513532
if link.is_wheel:
514533
# can raise InvalidWheelFilename
515534
wheel = Wheel(link.filename)
535+
536+
supported_variants = get_cached_variant_hashes_by_priority(
537+
self._variants_json.get(
538+
get_variants_json_filename(wheel)
539+
)
540+
)
541+
516542
try:
517543
pri = -(
518544
wheel.find_most_preferred_tag(
519545
valid_tags, self._wheel_tag_preferences
520546
)
521547
)
548+
variant_pri = -supported_variants.index(wheel.variant_hash)
522549
except ValueError:
523550
raise UnsupportedWheel(
524551
f"{wheel.filename} is not a supported wheel for this platform. It "
@@ -533,13 +560,15 @@ def _sort_key(self, candidate: InstallationCandidate) -> CandidateSortingKey:
533560
build_tag = (int(build_tag_groups[0]), build_tag_groups[1])
534561
else: # sdist
535562
pri = -(support_num)
563+
variant_pri = -sys.maxsize
536564
has_allowed_hash = int(link.is_hash_allowed(self._hashes))
537565
yank_value = -1 * int(link.is_yanked) # -1 for yanked.
538566
return (
539567
has_allowed_hash,
540568
yank_value,
541569
binary_preference,
542570
candidate.version,
571+
variant_pri,
543572
pri,
544573
build_tag,
545574
)
@@ -741,7 +770,7 @@ def _sort_links(self, links: Iterable[Link]) -> List[Link]:
741770
for link in links:
742771
if link not in seen:
743772
seen.add(link)
744-
if link.filename == "variants.json":
773+
if link.filename.endswith("-variants.json"):
745774
variants_json.append(link)
746775
elif link.egg_fragment:
747776
eggs.append(link)
@@ -784,10 +813,6 @@ def get_install_candidate(
784813
except InvalidVersion:
785814
return None
786815

787-
@functools.cache
788-
def get_variants_json(self, link: Link) -> dict:
789-
return VariantJson(self._link_collector.session.request("GET", link.url).json())
790-
791816
def evaluate_links(
792817
self, link_evaluator: LinkEvaluator, links: Iterable[Link]
793818
) -> List[InstallationCandidate]:
@@ -796,8 +821,11 @@ def evaluate_links(
796821
"""
797822
candidates = []
798823
for link in self._sort_links(links):
799-
if link.filename == "variants.json":
800-
link_evaluator.variants_json = self.get_variants_json(link)
824+
if link.filename.endswith("-variants.json"):
825+
link_evaluator.variants_json[link.filename] = VariantJson(
826+
link.url,
827+
lambda url: self._link_collector.session.request("GET", url).json(),
828+
)
801829
continue
802830

803831
candidate = self.get_install_candidate(link_evaluator, link)

src/pip/_internal/models/target_python.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ def format_given(self) -> str:
8181
)
8282

8383
def get_sorted_tags(self,
84-
variants_json: Optional[VariantJson] = None
8584
) -> List[Tag]:
8685
"""
8786
Return the supported PEP 425 tags to check wheel candidates against.
@@ -101,16 +100,12 @@ def get_sorted_tags(self,
101100
platforms=self.platforms,
102101
abis=self.abis,
103102
impl=self.implementation,
104-
variants_json=variants_json,
105103
)
106104

107105
def get_unsorted_tags(self,
108-
variants_json: Optional[VariantJson] = None
109106
) -> Set[Tag]:
110107
"""Exactly the same as get_sorted_tags, but returns a set.
111108
112109
This is important for performance.
113110
"""
114-
return set(self.get_sorted_tags(
115-
variants_json=variants_json,
116-
))
111+
return set(self.get_sorted_tags())

src/pip/_internal/models/wheel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def __init__(self, filename: str) -> None:
6666

6767
# All the tag combinations from this file
6868
self.file_tags = {
69-
Tag(x, y, z, self.variant_hash)
69+
Tag(x, y, z)
7070
for x in self.pyversions
7171
for y in self.abis
7272
for z in self.plats

src/pip/_internal/resolution/legacy/resolver.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ def _add_requirement_to_set(
225225
if install_req.link and install_req.link.is_wheel:
226226
wheel = Wheel(install_req.link.filename)
227227
tags = compatibility_tags.get_supported()
228+
raise NotImplementedError
228229
if requirement_set.check_supported_wheels and not wheel.supported(tags):
229230
raise InstallationError(
230231
f"{wheel.filename} is not a supported wheel on this platform."

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
from pip._internal.utils.compatibility_tags import get_supported
5454
from pip._internal.utils.hashes import Hashes
5555
from pip._internal.utils.packaging import get_requirement
56+
from pip._internal.utils.variant import variant_wheel_supported
5657
from pip._internal.utils.virtualenv import running_under_virtualenv
5758

5859
from .base import Candidate, Constraint, Requirement
@@ -141,7 +142,10 @@ def _fail_if_link_is_unsupported_wheel(self, link: Link) -> None:
141142
if not link.is_wheel:
142143
return
143144
wheel = Wheel(link.filename)
144-
if wheel.supported(self._finder.target_python.get_unsorted_tags()):
145+
if (
146+
wheel.supported(self._finder.target_python.get_unsorted_tags())
147+
and variant_wheel_supported(wheel, link)
148+
):
145149
return
146150
msg = f"{link.filename} is not a supported wheel on this platform."
147151
raise UnsupportedWheel(msg)

src/pip/_internal/utils/compatibility_tags.py

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@
1717
mac_platforms,
1818
)
1919

20-
from pip._internal.utils.variant import (
21-
VariantJson,
22-
get_cached_variant_hashes_by_priority,
23-
)
24-
2520
_apple_arch_pat = re.compile(r"(.+)_(\d+)_(\d+)_(.+)")
2621

2722

@@ -147,7 +142,6 @@ def get_supported(
147142
platforms: Optional[List[str]] = None,
148143
impl: Optional[str] = None,
149144
abis: Optional[List[str]] = None,
150-
variants_json: Optional[VariantJson] = None,
151145
) -> List[Tag]:
152146
"""Return a list of supported tags for each version specified in
153147
`versions`.
@@ -196,41 +190,4 @@ def get_supported(
196190
)
197191
)
198192

199-
if variants_json is not None:
200-
variants_by_priority = get_cached_variant_hashes_by_priority(
201-
variants_json=variants_json
202-
)
203-
204-
# NOTE: There is two choices implementation wise
205-
# QUESTION: Which one should be the outer loop ?
206-
#
207-
# 1. Shall it iterate over all variants per `Tag`:
208-
# - cp313-cp313-manylinux_2_36_aarch64-054fcdf8
209-
# - cp313-cp313-manylinux_2_35_aarch64-054fcdf8
210-
# - cp313-cp313-manylinux_2_34_aarch64-054fcdf8
211-
# - ...
212-
# - cp313-cp313-manylinux_2_36_aarch64-39614353
213-
# - cp313-cp313-manylinux_2_35_aarch64-39614353
214-
# - cp313-cp313-manylinux_2_34_aarch64-39614353
215-
# - ...
216-
#
217-
# 2. Shall it iterate over all tags per `Variants`:
218-
# - cp313-cp313-manylinux_2_36_aarch64-054fcdf8
219-
# - cp313-cp313-manylinux_2_36_aarch64-39614353
220-
# - ...
221-
# - cp313-cp313-manylinux_2_35_aarch64-054fcdf8
222-
# - cp313-cp313-manylinux_2_35_aarch64-39614353
223-
# - ...
224-
# - cp313-cp313-manylinux_2_34_aarch64-054fcdf8
225-
# - cp313-cp313-manylinux_2_34_aarch64-39614353
226-
# - ...
227-
228-
# Current implementation is choice 1)
229-
# Flip the order of `for loops` to switch to choice 2)
230-
supported = [
231-
Tag.create_varianttag_from_tag(tag, variant_hash=variant_hash)
232-
for variant_hash in variants_by_priority
233-
for tag in supported
234-
] + supported
235-
236193
return supported

0 commit comments

Comments
 (0)