From 77abfb895656f93e81e1684f051836614bb038ae Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sun, 15 Dec 2024 08:24:47 +0100 Subject: [PATCH] Ruff rules for comprehensions and performance --- micropip/externals/mousebender/simple.py | 33 ++++++++++++------------ micropip/install.py | 9 +++---- micropip/package.py | 3 +-- micropip/transaction.py | 8 +++--- micropip/wheelinfo.py | 3 ++- pyproject.toml | 17 +++++++----- tests/test_install.py | 2 +- tests/test_metadata.py | 2 +- 8 files changed, 40 insertions(+), 37 deletions(-) diff --git a/micropip/externals/mousebender/simple.py b/micropip/externals/mousebender/simple.py index 134bf05..0291766 100644 --- a/micropip/externals/mousebender/simple.py +++ b/micropip/externals/mousebender/simple.py @@ -5,11 +5,10 @@ import html.parser import urllib.parse import warnings -from typing import Any, Dict, List, Optional, Union, Literal, TypeAlias, TypedDict +from typing import Any, Dict, Literal, TypeAlias, TypedDict # noqa: UP035 mypy needs `Dict` import packaging.utils - ACCEPT_JSON_V1 = "application/vnd.pypi.simple.v1+json" @@ -38,17 +37,17 @@ class UnsupportedMIMEType(Exception): _Meta_1_1 = TypedDict("_Meta_1_1", {"api-version": Literal["1.1"]}) -_HashesDict: TypeAlias = Dict[str, str] +_HashesDict: TypeAlias = Dict[str, str] # noqa: UP006,UP040 mypy is not yet ready to for `type` and `dict`. _OptionalProjectFileDetails_1_0 = TypedDict( "_OptionalProjectFileDetails_1_0", { "requires-python": str, - "dist-info-metadata": Union[bool, _HashesDict], + "dist-info-metadata": bool | _HashesDict, "gpg-sig": bool, - "yanked": Union[bool, str], + "yanked": bool | str, # PEP-714 - "core-metadata": Union[bool, _HashesDict], + "core-metadata": bool | _HashesDict, }, total=False, ) @@ -66,13 +65,13 @@ class ProjectFileDetails_1_0(_OptionalProjectFileDetails_1_0): "_OptionalProjectFileDetails_1_1", { "requires-python": str, - "dist-info-metadata": Union[bool, _HashesDict], + "dist-info-metadata": bool | _HashesDict, "gpg-sig": bool, - "yanked": Union[bool, str], + "yanked": bool | str, # PEP 700 "upload-time": str, # PEP 714 - "core-metadata": Union[bool, _HashesDict], + "core-metadata": bool | _HashesDict, }, total=False, ) @@ -103,13 +102,13 @@ class ProjectDetails_1_1(TypedDict): name: packaging.utils.NormalizedName files: list[ProjectFileDetails_1_1] # PEP 700 - versions: List[str] + versions: list[str] -ProjectDetails: TypeAlias = Union[ProjectDetails_1_0, ProjectDetails_1_1] +ProjectDetails: TypeAlias = ProjectDetails_1_0 | ProjectDetails_1_1 # noqa: UP040 mypy is not yet ready to for `type`. -def _check_version(tag: str, attrs: Dict[str, Optional[str]]) -> None: +def _check_version(tag: str, attrs: dict[str, str | None]) -> None: if ( tag == "meta" and attrs.get("name") == "pypi:repository-version" @@ -126,11 +125,11 @@ def _check_version(tag: str, attrs: Dict[str, Optional[str]]) -> None: class _ArchiveLinkHTMLParser(html.parser.HTMLParser): def __init__(self) -> None: - self.archive_links: List[Dict[str, Any]] = [] + self.archive_links: list[dict[str, Any]] = [] super().__init__() def handle_starttag( - self, tag: str, attrs_list: list[tuple[str, Optional[str]]] + self, tag: str, attrs_list: list[tuple[str, str | None]] ) -> None: attrs = dict(attrs_list) _check_version(tag, attrs) @@ -149,7 +148,7 @@ def handle_starttag( _, _, raw_filename = parsed_url.path.rpartition("/") filename = urllib.parse.unquote(raw_filename) url = urllib.parse.urlunparse((*parsed_url[:5], "")) - args: Dict[str, Any] = {"filename": filename, "url": url} + args: dict[str, Any] = {"filename": filename, "url": url} # PEP 503: # The URL SHOULD include a hash in the form of a URL fragment with the # following syntax: #= ... @@ -210,7 +209,7 @@ def from_project_details_html(html: str, name: str) -> ProjectDetails_1_0: """ parser = _ArchiveLinkHTMLParser() parser.feed(html) - files: List[ProjectFileDetails_1_0] = [] + files: list[ProjectFileDetails_1_0] = [] for archive_link in parser.archive_links: details: ProjectFileDetails_1_0 = { "filename": archive_link["filename"], @@ -237,4 +236,4 @@ def from_project_details_html(html: str, name: str) -> ProjectDetails_1_0: "meta": {"api-version": "1.0"}, "name": packaging.utils.canonicalize_name(name), "files": files, - } \ No newline at end of file + } diff --git a/micropip/install.py b/micropip/install.py index 6cf75a0..5e32b50 100644 --- a/micropip/install.py +++ b/micropip/install.py @@ -28,7 +28,7 @@ async def install( if isinstance(requirements, str): requirements = [requirements] - fetch_kwargs = dict() + fetch_kwargs = {} if credentials: fetch_kwargs["credentials"] = credentials @@ -84,10 +84,9 @@ async def install( ) # Now install PyPI packages - for wheel in transaction.wheels: - # detect whether the wheel metadata is from PyPI or from custom location - # wheel metadata from PyPI has SHA256 checksum digest. - wheel_promises.append(wheel.install(wheel_base)) + # detect whether the wheel metadata is from PyPI or from custom location + # wheel metadata from PyPI has SHA256 checksum digest. + wheel_promises.extend(wheel.install(wheel_base) for wheel in transaction.wheels) await asyncio.gather(*wheel_promises) diff --git a/micropip/package.py b/micropip/package.py index aa06464..d39afa8 100644 --- a/micropip/package.py +++ b/micropip/package.py @@ -30,8 +30,7 @@ def format_row(values, widths, filler=""): rows.append(format_row(headers, col_width)) rows.append(format_row([""] * len(col_width), col_width, filler="-")) - for line in table: - rows.append(format_row(line, col_width)) + rows.extend(format_row(line, col_width) for line in table) return "\n".join(rows) diff --git a/micropip/transaction.py b/micropip/transaction.py index 9855db2..f29c48a 100644 --- a/micropip/transaction.py +++ b/micropip/transaction.py @@ -48,9 +48,9 @@ async def gather_requirements( self, requirements: list[str] | list[Requirement], ) -> None: - requirement_promises = [] - for requirement in requirements: - requirement_promises.append(self.add_requirement(requirement)) + requirement_promises = [ + self.add_requirement(requirement) for requirement in requirements + ] await asyncio.gather(*requirement_promises) @@ -132,7 +132,7 @@ def eval_marker(e: dict[str, str]) -> bool: # self.ctx_extras is empty and hence the eval_marker() function # will not be called at all. if not req.marker.evaluate(self.ctx) and not any( - [eval_marker(e) for e in self.ctx_extras] + eval_marker(e) for e in self.ctx_extras ): return # Is some version of this package is already installed? diff --git a/micropip/wheelinfo.py b/micropip/wheelinfo.py index 2c80b56..8e35f69 100644 --- a/micropip/wheelinfo.py +++ b/micropip/wheelinfo.py @@ -52,7 +52,8 @@ class WheelInfo: _metadata: Metadata | None = None # Wheel metadata. _requires: list[Requirement] | None = None # List of requirements. - # Path to the .dist-info directory. This is only available after extracting the wheel, i.e. after calling `extract()`. + # Path to the .dist-info directory. + # This is only available after extracting the wheel, i.e. after calling `extract()`. _dist_info: Path | None = None def __post_init__(self): diff --git a/pyproject.toml b/pyproject.toml index b481317..f4c38b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,17 +39,22 @@ build-backend = "setuptools.build_meta" write_to = "micropip/_version.py" [tool.ruff] -line-length = 122 +line-length = 120 lint.select = [ - "E", # pycodestyles - "W", # pycodestyles - "F", # pyflakes "B", # bugbear - "UP", # pyupgrade + "C4", # flake8-comprehensions + "C90", # mccabe code complexity + "E", # pycodestyle errors + "F", # pyflakes + "G", # flake8-logging-format "I", # isort + "PERF", # perflint "PGH", # pygrep-hooks - "G", # flake8-logging-format + "UP", # pyupgrade + "W", # pycodestyle whitespace ] +lint.flake8-comprehensions.allow-dict-calls-with-keyword-arguments = true +lint.mccabe.max-complexity = 13 target-version = "py312" [tool.ruff.lint.isort] diff --git a/tests/test_install.py b/tests/test_install.py index aa0d22e..9b7f7bc 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -249,7 +249,7 @@ async def test_install_with_credentials(selenium): fetch_response_mock = MagicMock() async def myfunc(): - return json.dumps(dict()) + return json.dumps({}) fetch_response_mock.string.side_effect = myfunc diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 42fe80f..cf4d7a3 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -35,7 +35,7 @@ def test_Metadata_requires(metadata_path, extras, expected): m = Metadata(metadata) reqs = m.requires(extras) - reqs_set = set([r.name for r in reqs]) + reqs_set = {r.name for r in reqs} assert reqs_set == set(expected)