From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 4 Nov 2025 18:17:57 +0000 (+0200) Subject: [3.13] gh-139590: Stricter `ruff` rules for `Tools/wasm` (GH-139752) (#140986) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=56146059d3479c04a65805f5326e7200cf7040b7;p=thirdparty%2FPython%2Fcpython.git [3.13] gh-139590: Stricter `ruff` rules for `Tools/wasm` (GH-139752) (#140986) Co-authored-by: sobolevn --- diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index ba30e027d98b..ccf3ca11293d 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -27,7 +27,6 @@ on: - "Tools/jit/**" - "Tools/peg_generator/**" - "Tools/requirements-dev.txt" - - "Tools/wasm/**" workflow_dispatch: permissions: @@ -59,7 +58,6 @@ jobs: "Tools/clinic", "Tools/jit", "Tools/peg_generator", - "Tools/wasm", ] steps: - uses: actions/checkout@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa5dab0ad16d..6347ffb3e119 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,6 +22,10 @@ repos: name: Run Ruff (lint) on Tools/peg_generator/ args: [--exit-non-zero-on-fix, --config=Tools/peg_generator/.ruff.toml] files: ^Tools/peg_generator/ + - id: ruff-check + name: Run Ruff (lint) on Tools/wasm/ + args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml] + files: ^Tools/wasm/ - id: ruff-format name: Run Ruff (format) on Doc/ args: [--check] diff --git a/Tools/wasm/.ruff.toml b/Tools/wasm/.ruff.toml index aabcf8dc4f50..3d8e59fa3f22 100644 --- a/Tools/wasm/.ruff.toml +++ b/Tools/wasm/.ruff.toml @@ -22,7 +22,4 @@ select = [ ] ignore = [ "E501", # Line too long - "F541", # f-string without any placeholders - "PYI024", # Use `typing.NamedTuple` instead of `collections.namedtuple` - "PYI025", # Use `from collections.abc import Set as AbstractSet` ] diff --git a/Tools/wasm/mypy.ini b/Tools/wasm/mypy.ini deleted file mode 100644 index 4de0a30c260f..000000000000 --- a/Tools/wasm/mypy.ini +++ /dev/null @@ -1,11 +0,0 @@ -[mypy] -files = Tools/wasm/wasm_*.py -pretty = True -show_traceback = True - -# Make sure the wasm can be run using Python 3.8: -python_version = 3.8 - -# Be strict... -strict = True -enable_error_code = truthy-bool,ignore-without-code diff --git a/Tools/wasm/wasi.py b/Tools/wasm/wasi.py index 34051bd7351a..3f76900fc60a 100644 --- a/Tools/wasm/wasi.py +++ b/Tools/wasm/wasi.py @@ -16,14 +16,13 @@ import sys import sysconfig import tempfile - CHECKOUT = pathlib.Path(__file__).parent.parent.parent CROSS_BUILD_DIR = CHECKOUT / "cross-build" BUILD_DIR = CROSS_BUILD_DIR / "build" LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" -LOCAL_SETUP_MARKER = "# Generated by Tools/wasm/wasi.py\n".encode("utf-8") +LOCAL_SETUP_MARKER = b"# Generated by Tools/wasm/wasi.py\n" WASMTIME_VAR_NAME = "WASMTIME" WASMTIME_HOST_RUNNER_VAR = f"{{{WASMTIME_VAR_NAME}}}" @@ -84,7 +83,7 @@ def subdir(working_dir, *, clean_ok=False): and getattr(context, "clean", False) and working_dir.exists() ): - print(f"🚮 Deleting directory (--clean)...") + print("🚮 Deleting directory (--clean)...") shutil.rmtree(working_dir) working_dir.mkdir(parents=True, exist_ok=True) @@ -372,7 +371,7 @@ def main(): make_host = subcommands.add_parser( "make-host", help="Run `make` for the host/WASI" ) - clean = subcommands.add_parser( + subcommands.add_parser( "clean", help="Delete files and directories created by this script" ) for subcommand in ( diff --git a/Tools/wasm/wasm_assets.py b/Tools/wasm/wasm_assets.py index 6cfb73a95257..8229ab62f272 100755 --- a/Tools/wasm/wasm_assets.py +++ b/Tools/wasm/wasm_assets.py @@ -16,7 +16,6 @@ import shutil import sys import sysconfig import zipfile -from typing import Dict # source directory SRCDIR = pathlib.Path(__file__).parent.parent.parent.absolute() @@ -147,7 +146,7 @@ def create_stdlib_zip( pzf.writepy(entry, filterfunc=filterfunc) -def detect_extension_modules(args: argparse.Namespace) -> Dict[str, bool]: +def detect_extension_modules(args: argparse.Namespace) -> dict[str, bool]: modules = {} # disabled by Modules/Setup.local ? @@ -162,7 +161,7 @@ def detect_extension_modules(args: argparse.Namespace) -> Dict[str, bool]: # disabled by configure? with open(args.sysconfig_data) as f: data = f.read() - loc: Dict[str, Dict[str, str]] = {} + loc: dict[str, dict[str, str]] = {} exec(data, globals(), loc) for key, value in loc["build_time_vars"].items(): diff --git a/Tools/wasm/wasm_build.py b/Tools/wasm/wasm_build.py index 5cc1c06f4a27..d9f7dd92ba1f 100755 --- a/Tools/wasm/wasm_build.py +++ b/Tools/wasm/wasm_build.py @@ -23,8 +23,8 @@ changes. """ import argparse -import enum import dataclasses +import enum import logging import os import pathlib @@ -39,18 +39,12 @@ import tempfile import time import warnings import webbrowser +from collections.abc import Callable, Iterable # for Python 3.8 from typing import ( - cast, Any, - Callable, - Dict, - Iterable, - List, - Optional, - Tuple, - Union, + cast, ) logger = logging.getLogger("wasm_build") @@ -122,7 +116,7 @@ https://wasmtime.dev/ to install wasmtime. def parse_emconfig( emconfig: pathlib.Path = EM_CONFIG, -) -> Tuple[pathlib.Path, pathlib.Path]: +) -> tuple[pathlib.Path, pathlib.Path]: """Parse EM_CONFIG file and lookup EMSCRIPTEN_ROOT and NODE_JS. The ".emscripten" config file is a Python snippet that uses "EM_CONFIG" @@ -134,7 +128,7 @@ def parse_emconfig( with open(emconfig, encoding="utf-8") as f: code = f.read() # EM_CONFIG file is a Python snippet - local: Dict[str, Any] = {} + local: dict[str, Any] = {} exec(code, globals(), local) emscripten_root = pathlib.Path(local["EMSCRIPTEN_ROOT"]) node_js = pathlib.Path(local["NODE_JS"]) @@ -192,16 +186,16 @@ class Platform: name: str pythonexe: str - config_site: Optional[pathlib.PurePath] - configure_wrapper: Optional[pathlib.Path] - make_wrapper: Optional[pathlib.PurePath] - environ: Dict[str, Any] + config_site: pathlib.PurePath | None + configure_wrapper: pathlib.Path | None + make_wrapper: pathlib.PurePath | None + environ: dict[str, Any] check: Callable[[], None] # Used for build_emports(). - ports: Optional[pathlib.PurePath] - cc: Optional[pathlib.PurePath] + ports: pathlib.PurePath | None + cc: pathlib.PurePath | None - def getenv(self, profile: "BuildProfile") -> Dict[str, Any]: + def getenv(self, profile: "BuildProfile") -> dict[str, Any]: return self.environ.copy() @@ -264,7 +258,7 @@ def _check_emscripten() -> None: # git / upstream / tot-upstream installation version = version[:-4] version_tuple = cast( - Tuple[int, int, int], tuple(int(v) for v in version.split(".")) + tuple[int, int, int], tuple(int(v) for v in version.split(".")) ) if version_tuple < EMSDK_MIN_VERSION: raise ConditionError( @@ -388,7 +382,7 @@ class Host(enum.Enum): return [] @property - def emport_args(self) -> List[str]: + def emport_args(self) -> list[str]: """Host-specific port args (Emscripten).""" cls = type(self) if self is cls.wasm64_emscripten: @@ -399,7 +393,7 @@ class Host(enum.Enum): return [] @property - def embuilder_args(self) -> List[str]: + def embuilder_args(self) -> list[str]: """Host-specific embuilder args (Emscripten).""" cls = type(self) if self is cls.wasm64_emscripten: @@ -422,7 +416,7 @@ class EmscriptenTarget(enum.Enum): return self in {cls.browser, cls.browser_debug} @property - def emport_args(self) -> List[str]: + def emport_args(self) -> list[str]: """Target-specific port args.""" cls = type(self) if self in {cls.browser_debug, cls.node_debug}: @@ -448,9 +442,9 @@ class BuildProfile: name: str support_level: SupportLevel host: Host - target: Union[EmscriptenTarget, None] = None - dynamic_linking: Union[bool, None] = None - pthreads: Union[bool, None] = None + target: EmscriptenTarget | None = None + dynamic_linking: bool | None = None + pthreads: bool | None = None default_testopts: str = "-j2" @property @@ -474,7 +468,7 @@ class BuildProfile: return self.builddir / "Makefile" @property - def configure_cmd(self) -> List[str]: + def configure_cmd(self) -> list[str]: """Generate configure command""" # use relative path, so WASI tests can find lib prefix. # pathlib.Path.relative_to() does not work here. @@ -509,7 +503,7 @@ class BuildProfile: return cmd @property - def make_cmd(self) -> List[str]: + def make_cmd(self) -> list[str]: """Generate make command""" cmd = ["make"] platform = self.host.platform @@ -517,7 +511,7 @@ class BuildProfile: cmd.insert(0, os.fspath(platform.make_wrapper)) return cmd - def getenv(self) -> Dict[str, Any]: + def getenv(self) -> dict[str, Any]: """Generate environ dict for platform""" env = os.environ.copy() if hasattr(os, "process_cpu_count"): @@ -531,7 +525,7 @@ class BuildProfile: env.pop(key, None) elif key == "PATH": # list of path items, prefix with extra paths - new_path: List[pathlib.PurePath] = [] + new_path: list[pathlib.PurePath] = [] new_path.extend(self.host.get_extra_paths()) new_path.extend(value) env[key] = os.pathsep.join(os.fspath(p) for p in new_path) @@ -549,7 +543,7 @@ class BuildProfile: self, cmd: Iterable[str], args: Iterable[str] = (), - cwd: Optional[pathlib.Path] = None, + cwd: pathlib.Path | None = None, ) -> int: cmd = list(cmd) cmd.extend(args) @@ -587,7 +581,7 @@ class BuildProfile: self._check_execute() return self.run_make("pythoninfo", *args) - def run_test(self, target: str, testopts: Optional[str] = None) -> int: + def run_test(self, target: str, testopts: str | None = None) -> int: """Run buildbottests""" self._check_execute() if testopts is None: @@ -823,10 +817,8 @@ parser.add_argument( ) # Don't list broken and experimental variants in help -platforms_choices = list(p.name for p in _profiles) + ["cleanall"] -platforms_help = list(p.name for p in _profiles if p.support_level) + [ - "cleanall" -] +platforms_choices = [p.name for p in _profiles] + ["cleanall"] +platforms_help = [p.name for p in _profiles if p.support_level] + ["cleanall"] parser.add_argument( "platform", metavar="PLATFORM", @@ -834,18 +826,18 @@ parser.add_argument( choices=platforms_choices, ) -ops = dict( - build="auto build (build 'build' Python, emports, configure, compile)", - configure="run ./configure", - compile="run 'make all'", - pythoninfo="run 'make pythoninfo'", - test="run 'make buildbottest TESTOPTS=...' (supports parallel tests)", - hostrunnertest="run 'make hostrunnertest TESTOPTS=...'", - repl="start interactive REPL / webserver + browser session", - clean="run 'make clean'", - cleanall="remove all build directories", - emports="build Emscripten port with embuilder (only Emscripten)", -) +ops = { + "build": "auto build (build 'build' Python, emports, configure, compile)", + "configure": "run ./configure", + "compile": "run 'make all'", + "pythoninfo": "run 'make pythoninfo'", + "test": "run 'make buildbottest TESTOPTS=...' (supports parallel tests)", + "hostrunnertest": "run 'make hostrunnertest TESTOPTS=...'", + "repl": "start interactive REPL / webserver + browser session", + "clean": "run 'make clean'", + "cleanall": "remove all build directories", + "emports": "build Emscripten port with embuilder (only Emscripten)", +} ops_help = "\n".join(f"{op:16s} {help}" for op, help in ops.items()) parser.add_argument( "ops",