python (3.11.7)
       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)