From 89d9b95d38355a22670cf7cce44f6ecc3c1b85d8 Mon Sep 17 00:00:00 2001 From: ryanking13 Date: Fri, 22 Sep 2023 22:30:51 +0900 Subject: [PATCH] Fix lint --- micropip/_compat_not_in_pyodide.py | 1 - micropip/metadata.py | 33 ++++++++++++++++-------------- micropip/transaction.py | 2 +- micropip/wheelinfo.py | 9 ++++++-- tests/test_metadata.py | 24 ++++++++++++++-------- 5 files changed, 42 insertions(+), 27 deletions(-) diff --git a/micropip/_compat_not_in_pyodide.py b/micropip/_compat_not_in_pyodide.py index 271ebb1..c229aa9 100644 --- a/micropip/_compat_not_in_pyodide.py +++ b/micropip/_compat_not_in_pyodide.py @@ -2,7 +2,6 @@ from io import BytesIO from pathlib import Path from typing import IO, Any -from zipfile import ZipFile REPODATA_PACKAGES: dict[str, dict[str, Any]] = {} diff --git a/micropip/metadata.py b/micropip/metadata.py index c0bf978..9131a28 100644 --- a/micropip/metadata.py +++ b/micropip/metadata.py @@ -1,12 +1,13 @@ """ This is a stripped down version of pip._vendor.pkg_resources.DistInfoDistribution """ +import re +import zipfile +from collections.abc import Iterable from pathlib import Path + from packaging.requirements import Requirement from packaging.utils import canonicalize_name -import re -from collections.abc import Sequence -import zipfile def safe_name(name): @@ -69,6 +70,7 @@ class Metadata: """ Represents a metadata file in a wheel """ + PKG_INFO = "METADATA" REQUIRES_DIST = "Requires-Dist:" PROVIDES_EXTRA = "Provides-Extra:" @@ -78,23 +80,24 @@ def __init__(self, path: Path | zipfile.Path): self.deps = self._compute_dependencies() def _parse_requirement(self, line: str) -> Requirement: - line = line[len(self.REQUIRES_DIST):] + line = line[len(self.REQUIRES_DIST) :] if " #" in line: line = line[: line.find(" #")] - + return Requirement(line.strip()) - def _compute_dependencies(self) -> dict[str, frozenset[str]]: + def _compute_dependencies(self) -> dict[str | None, frozenset[Requirement]]: """ Compute the dependencies of the metadata file """ - deps: dict[str, frozenset[str]] = {} + deps: dict[str | None, frozenset[Requirement]] = {} reqs: list[Requirement] = [] extras: list[str] = [] - def reqs_for_extra(extra: str) -> Requirement: + def reqs_for_extra(extra: str | None) -> Iterable[Requirement]: + environment = {"extra": extra} if extra else None for req in reqs: - if not req.marker or req.marker.evaluate({"extra": extra}): + if not req.marker or req.marker.evaluate(environment): yield req lines = self.path.read_text(encoding="utf-8").splitlines() @@ -102,22 +105,22 @@ def reqs_for_extra(extra: str) -> Requirement: if line.startswith(self.REQUIRES_DIST): reqs.append(self._parse_requirement(line)) elif line.startswith(self.PROVIDES_EXTRA): - extras.append(line[len(self.PROVIDES_EXTRA):].strip()) + extras.append(line[len(self.PROVIDES_EXTRA) :].strip()) deps[None] = frozenset(reqs_for_extra(None)) for extra in extras: deps[safe_extra(extra)] = frozenset(reqs_for_extra(extra)) - deps[None] return deps - - def requires(self, extras: Sequence[str]=()) -> list[Requirement]: + + def requires(self, extras: Iterable[str] = ()) -> list[Requirement]: """List of Requirements needed for this distro if `extras` are used""" - deps = [] + deps: list[Requirement] = [] + deps.extend(self.deps.get(None, ())) for ext in extras: try: deps.extend(self.deps[safe_extra(ext)]) except KeyError: - raise KeyError(f"Unknown extra {ext!r}") + raise KeyError(f"Unknown extra {ext!r}") from None return deps - \ No newline at end of file diff --git a/micropip/transaction.py b/micropip/transaction.py index ee95a3a..bbc91e2 100644 --- a/micropip/transaction.py +++ b/micropip/transaction.py @@ -46,7 +46,7 @@ def __post_init__(self): async def gather_requirements( self, - requirements: list[str], + requirements: list[str] | list[Requirement], ) -> None: requirement_promises = [] for requirement in requirements: diff --git a/micropip/wheelinfo.py b/micropip/wheelinfo.py index dfc98c3..e831fdd 100644 --- a/micropip/wheelinfo.py +++ b/micropip/wheelinfo.py @@ -1,11 +1,11 @@ import asyncio import hashlib import json +import zipfile from dataclasses import dataclass from pathlib import Path from typing import IO, Any from urllib.parse import ParseResult, urlparse -import zipfile from packaging.requirements import Requirement from packaging.tags import Tag @@ -123,10 +123,15 @@ async def download(self, fetch_kwargs: dict[str, Any]): metadata_path = wheel_dist_info_dir(zf, self.name) + "/" + Metadata.PKG_INFO self._metadata = Metadata(zipfile.Path(zf, metadata_path)) - def requires(self, extras: set[str]) -> list[str]: + def requires(self, extras: set[str]) -> list[Requirement]: """ Get a list of requirements for the wheel. """ + if self._metadata is None: + raise RuntimeError( + "Micropip internal error: attempted to get requirements before downloading the wheel?" + ) + requires = self._metadata.requires(extras) self._requires = requires return requires diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 9939e63..4aefe86 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -1,33 +1,38 @@ from pathlib import Path + import pytest TEST_METADATA_DIR = Path(__file__).parent / "test_data" / "metadata" + @pytest.mark.parametrize( "metadata_path, extras, expected", [ ( "boto3-1.28.51-py3-none-any.whl.metadata", (), - ["botocore", "jmespath", "s3transfer"] + ["botocore", "jmespath", "s3transfer"], ), ( "requests-2.31.0-py3-none-any.whl.metadata", (), - ["certifi", "urllib3", "charset-normalizer", "idna"] + ["certifi", "urllib3", "charset-normalizer", "idna"], ), ( "requests-2.31.0-py3-none-any.whl.metadata", - ("socks", "use_chardet_on_py3",), - ["certifi", "urllib3", "charset-normalizer", "idna", "PySocks", "chardet"] + ( + "socks", + "use_chardet_on_py3", + ), + ["certifi", "urllib3", "charset-normalizer", "idna", "PySocks", "chardet"], ), - ] + ], ) def test_Metadata_requires(metadata_path, extras, expected): from micropip.metadata import Metadata m = Metadata(TEST_METADATA_DIR / metadata_path) - + reqs = m.requires(extras) reqs_set = set([r.name for r in reqs]) assert reqs_set == set(expected) @@ -53,7 +58,10 @@ def test_Metadata_marker(): markers = {r.name: str(r.marker) for r in reqs} assert "brotli" in markers - assert markers["brotli"] == 'platform_python_implementation == "CPython" and extra == "brotli"' + assert ( + markers["brotli"] + == 'platform_python_implementation == "CPython" and extra == "brotli"' + ) assert "zstandard" in markers assert markers["zstandard"] == 'extra == "zstd"' @@ -69,4 +77,4 @@ def test_Metadata_extra_of_requires(): reqs_set = {r.name: r.extras for r in reqs} assert "botocore" in reqs_set - assert reqs_set["botocore"] == {"crt"} \ No newline at end of file + assert reqs_set["botocore"] == {"crt"}