diff --git a/micropip/_utils.py b/micropip/_utils.py index 9abab9d..8bbc62e 100644 --- a/micropip/_utils.py +++ b/micropip/_utils.py @@ -117,7 +117,7 @@ def best_compatible_tag_index(tags: frozenset[Tag]) -> int | None: return None -def is_package_compatible(filename: str) -> bool: +def is_package_compatible(filename: str) -> tuple[bool, int | None]: """ Check if a package is compatible with the current platform. @@ -128,17 +128,15 @@ def is_package_compatible(filename: str) -> bool: """ if not filename.endswith(".whl"): - return False - - if filename.endswith("py3-none-any.whl"): - return True + return False, None try: tags = parse_tags(filename) except (InvalidVersion, InvalidWheelFilename): - return False + return False, None - return best_compatible_tag_index(tags) is not None + tag_index = best_compatible_tag_index(tags) + return (tag_index is not None), tag_index def check_compatible(filename: str) -> None: @@ -146,7 +144,7 @@ def check_compatible(filename: str) -> None: Check if a package is compatible with the current platform. If not, raise an exception with a error message that explains why. """ - compatible = is_package_compatible(filename) + compatible, _ = is_package_compatible(filename) if compatible: return diff --git a/micropip/package_index.py b/micropip/package_index.py index c7e4d08..b433a26 100644 --- a/micropip/package_index.py +++ b/micropip/package_index.py @@ -147,7 +147,7 @@ def _compatible_wheels( # Checking compatibility takes a bit of time, # so we use a generator to avoid doing it for all files. - compatible = is_package_compatible(filename) + compatible, tag_index = is_package_compatible(filename) if not compatible: continue @@ -177,6 +177,7 @@ def _compatible_wheels( size=size, core_metadata=core_metadata, yanked_reason=yanked_reason, + best_tag_index=tag_index, ) @classmethod diff --git a/micropip/transaction.py b/micropip/transaction.py index 3f6f1f8..abadffb 100644 --- a/micropip/transaction.py +++ b/micropip/transaction.py @@ -10,7 +10,6 @@ from . import package_index from ._compat import CompatibilityLayer from ._utils import ( - best_compatible_tag_index, check_compatible, constrain_requirement, validate_constraints, @@ -413,7 +412,7 @@ def _find_best_wheel(wheels: Iterable[WheelInfo]) -> WheelInfo | None: best_wheel = None best_tag_index = float("infinity") for wheel in wheels: - tag_index = best_compatible_tag_index(wheel.tags) + tag_index = wheel.best_tag_index if tag_index is not None and tag_index < best_tag_index: best_wheel = wheel best_tag_index = tag_index diff --git a/micropip/wheelinfo.py b/micropip/wheelinfo.py index d545dad..43cf378 100644 --- a/micropip/wheelinfo.py +++ b/micropip/wheelinfo.py @@ -13,7 +13,7 @@ loadedPackages, to_js, ) -from ._utils import parse_wheel_filename +from ._utils import best_compatible_tag_index, parse_wheel_filename from ._vendored.packaging.src.packaging.requirements import Requirement from ._vendored.packaging.src.packaging.tags import Tag from ._vendored.packaging.src.packaging.version import Version @@ -47,6 +47,7 @@ class WheelInfo: yanked_reason: str | bool = ( False # Whether the wheel has been yanked and the reason (if given) (PEP-592) ) + _best_tag_index: int | None = field(default=None, repr=False, compare=False) # Fields below are only available after downloading the wheel, i.e. after calling `download()`. @@ -62,6 +63,15 @@ def __post_init__(self): self.metadata_url = self.url + ".metadata" self.yanked = bool(self.yanked_reason) + @property + def best_tag_index(self) -> int | None: + """ + Returns an index if a compatible tag exists, otherwise None. + """ + if self._best_tag_index is None: + self._best_tag_index = best_compatible_tag_index(self.tags) + return self._best_tag_index + @classmethod def from_url(cls, url: str) -> "WheelInfo": """Parse wheels URL and extract available metadata @@ -101,6 +111,7 @@ def from_package_index( size: int | None, core_metadata: DistributionMetadata = None, yanked_reason: str | bool = False, + best_tag_index: int | None = None, ) -> "WheelInfo": """Extract available metadata from response received from package index""" parsed_url = urlparse(url) @@ -118,6 +129,7 @@ def from_package_index( size=size, core_metadata=core_metadata, yanked_reason=yanked_reason, + _best_tag_index=best_tag_index, ) async def install(self, target: Path) -> None: