"""Represents a wheel file and provides access to the various parts of the
name that have meaning.
"""
import re
from typing
import Dict, Iterable, List
from pip._vendor.packaging.tags
import Tag
from pip._internal.exceptions
import InvalidWheelFilename
class Wheel:
"""A wheel file"""
wheel_file_re = re.compile(
r
"""^(?P(?P[^\s-]+?)-(?P[^\s-]*?))
((-(?P<build>\d[^-]*?))?-(?P<pyver>[^\s-]+?)-(?P<abi>[^\s-]+?)-(?P<plat>[^\s-]+?)
\.whl|\.dist-info)$
""",
re.VERBOSE,
)
def __init__(self, filename: str) ->
None:
"""
:raises InvalidWheelFilename: when the filename
is invalid
for a wheel
"""
wheel_info = self.wheel_file_re.match(filename)
if not wheel_info:
raise InvalidWheelFilename(f
"{filename} is not a valid wheel filename.")
self.filename = filename
self.name = wheel_info.group(
"name").replace(
"_",
"-")
# we'll assume "_" means "-" due to wheel naming scheme
# (https://github.com/pypa/pip/issues/1150)
self.version = wheel_info.group(
"ver").replace(
"_",
"-")
self.build_tag = wheel_info.group(
"build")
self.pyversions = wheel_info.group(
"pyver").split(
".")
self.abis = wheel_info.group(
"abi").split(
".")
self.plats = wheel_info.group(
"plat").split(
".")
# All the tag combinations from this file
self.file_tags = {
Tag(x, y, z)
for x
in self.pyversions
for y
in self.abis
for z
in self.plats
}
def get_formatted_file_tags(self) -> List[str]:
"""Return the wheel's tags as a sorted list of strings."""
return sorted(str(tag)
for tag
in self.file_tags)
def support_index_min(self, tags: List[Tag]) -> int:
"""Return the lowest index that one of the wheel's file_tag combinations
achieves
in the given list of supported tags.
For example,
if there are 8 supported tags
and one of the file tags
is first
in the list, then
return 0.
:param tags: the PEP 425 tags to check the wheel against,
in order
with most preferred first.
:raises ValueError:
If none of the wheel
's file tags match one of
the supported tags.
"""
try:
return next(i
for i, t
in enumerate(tags)
if t
in self.file_tags)
except StopIteration:
raise ValueError()
def find_most_preferred_tag(
self, tags: List[Tag], tag_to_priority: Dict[Tag, int]
) -> int:
"""Return the priority of the most preferred tag that one of the wheel's file
tag combinations achieves
in the given list of supported tags using the given
tag_to_priority mapping, where lower priorities are more-preferred.
This
is used
in place of support_index_min
in some cases
in order to avoid
an expensive linear scan of a large list of tags.
:param tags: the PEP 425 tags to check the wheel against.
:param tag_to_priority: a mapping
from tag to priority of that tag, where
lower
is more preferred.
:raises ValueError:
If none of the wheel
's file tags match one of
the supported tags.
"""
return min(
tag_to_priority[tag]
for tag
in self.file_tags
if tag
in tag_to_priority
)
def supported(self, tags: Iterable[Tag]) -> bool:
"""Return whether the wheel is compatible with one of the given tags.
:param tags: the PEP 425 tags to check the wheel against.
"""
return not self.file_tags.isdisjoint(tags)