python (3.12.0)
1 """Represents a wheel file and provides access to the various parts of the
2 name that have meaning.
3 """
4 import re
5 from typing import Dict, Iterable, List
6
7 from pip._vendor.packaging.tags import Tag
8
9 from pip._internal.exceptions import InvalidWheelFilename
10
11
12 class ESC[4;38;5;81mWheel:
13 """A wheel file"""
14
15 wheel_file_re = re.compile(
16 r"""^(?P<namever>(?P<name>[^\s-]+?)-(?P<ver>[^\s-]*?))
17 ((-(?P<build>\d[^-]*?))?-(?P<pyver>[^\s-]+?)-(?P<abi>[^\s-]+?)-(?P<plat>[^\s-]+?)
18 \.whl|\.dist-info)$""",
19 re.VERBOSE,
20 )
21
22 def __init__(self, filename: str) -> None:
23 """
24 :raises InvalidWheelFilename: when the filename is invalid for a wheel
25 """
26 wheel_info = self.wheel_file_re.match(filename)
27 if not wheel_info:
28 raise InvalidWheelFilename(f"{filename} is not a valid wheel filename.")
29 self.filename = filename
30 self.name = wheel_info.group("name").replace("_", "-")
31 # we'll assume "_" means "-" due to wheel naming scheme
32 # (https://github.com/pypa/pip/issues/1150)
33 self.version = wheel_info.group("ver").replace("_", "-")
34 self.build_tag = wheel_info.group("build")
35 self.pyversions = wheel_info.group("pyver").split(".")
36 self.abis = wheel_info.group("abi").split(".")
37 self.plats = wheel_info.group("plat").split(".")
38
39 # All the tag combinations from this file
40 self.file_tags = {
41 Tag(x, y, z) for x in self.pyversions for y in self.abis for z in self.plats
42 }
43
44 def get_formatted_file_tags(self) -> List[str]:
45 """Return the wheel's tags as a sorted list of strings."""
46 return sorted(str(tag) for tag in self.file_tags)
47
48 def support_index_min(self, tags: List[Tag]) -> int:
49 """Return the lowest index that one of the wheel's file_tag combinations
50 achieves in the given list of supported tags.
51
52 For example, if there are 8 supported tags and one of the file tags
53 is first in the list, then return 0.
54
55 :param tags: the PEP 425 tags to check the wheel against, in order
56 with most preferred first.
57
58 :raises ValueError: If none of the wheel's file tags match one of
59 the supported tags.
60 """
61 try:
62 return next(i for i, t in enumerate(tags) if t in self.file_tags)
63 except StopIteration:
64 raise ValueError()
65
66 def find_most_preferred_tag(
67 self, tags: List[Tag], tag_to_priority: Dict[Tag, int]
68 ) -> int:
69 """Return the priority of the most preferred tag that one of the wheel's file
70 tag combinations achieves in the given list of supported tags using the given
71 tag_to_priority mapping, where lower priorities are more-preferred.
72
73 This is used in place of support_index_min in some cases in order to avoid
74 an expensive linear scan of a large list of tags.
75
76 :param tags: the PEP 425 tags to check the wheel against.
77 :param tag_to_priority: a mapping from tag to priority of that tag, where
78 lower is more preferred.
79
80 :raises ValueError: If none of the wheel's file tags match one of
81 the supported tags.
82 """
83 return min(
84 tag_to_priority[tag] for tag in self.file_tags if tag in tag_to_priority
85 )
86
87 def supported(self, tags: Iterable[Tag]) -> bool:
88 """Return whether the wheel is compatible with one of the given tags.
89
90 :param tags: the PEP 425 tags to check the wheel against.
91 """
92 return not self.file_tags.isdisjoint(tags)