From b6a2be329622d065ecc157311cdf113d2ec63997 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Thu, 9 Oct 2025 01:13:27 +0300 Subject: [PATCH 1/4] gh-139590: Stricter `ruff` rules for `Tools/wasm` (GH-139752) (cherry picked from commit 678e0b818c0d6063907f55263bbc0e194b492c8e) Co-authored-by: sobolevn --- .pre-commit-config.yaml | 4 ++++ Tools/wasm/.ruff.toml | 3 --- Tools/wasm/emscripten/__main__.py | 9 ++++----- Tools/wasm/emscripten/wasm_assets.py | 5 ++--- Tools/wasm/wasi/__main__.py | 10 ++++------ 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e00ffb3bd2d66..b0311f052798ad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,6 +26,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 aabcf8dc4f502e..3d8e59fa3f22c4 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/emscripten/__main__.py b/Tools/wasm/emscripten/__main__.py index fdf3142c0a3b1a..c88e9edba6d230 100644 --- a/Tools/wasm/emscripten/__main__.py +++ b/Tools/wasm/emscripten/__main__.py @@ -3,16 +3,16 @@ import argparse import contextlib import functools +import hashlib import os import shutil import subprocess import sys import sysconfig -import hashlib import tempfile -from urllib.request import urlopen from pathlib import Path from textwrap import dedent +from urllib.request import urlopen try: from os import process_cpu_count as cpu_count @@ -33,9 +33,7 @@ PREFIX_DIR = CROSS_BUILD_DIR / HOST_TRIPLE / "prefix" LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" -LOCAL_SETUP_MARKER = "# Generated by Tools/wasm/emscripten.py\n".encode( - "utf-8" -) +LOCAL_SETUP_MARKER = b"# Generated by Tools/wasm/emscripten.py\n" def updated_env(updates={}): @@ -432,6 +430,7 @@ def main(): make_build, configure_host, make_host, + clean, ): subcommand.add_argument( "--quiet", diff --git a/Tools/wasm/emscripten/wasm_assets.py b/Tools/wasm/emscripten/wasm_assets.py index 90f318f319a9f1..384790872353b2 100755 --- a/Tools/wasm/emscripten/wasm_assets.py +++ b/Tools/wasm/emscripten/wasm_assets.py @@ -15,7 +15,6 @@ import sys import sysconfig import zipfile -from typing import Dict # source directory SRCDIR = pathlib.Path(__file__).parents[3].absolute() @@ -134,7 +133,7 @@ def filterfunc(filename: str) -> bool: 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 ? @@ -149,7 +148,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/wasi/__main__.py b/Tools/wasm/wasi/__main__.py index a0658cb351a86f..b2f643ddbfc213 100644 --- a/Tools/wasm/wasi/__main__.py +++ b/Tools/wasm/wasi/__main__.py @@ -16,7 +16,6 @@ import sysconfig import tempfile - CHECKOUT = pathlib.Path(__file__).parent.parent.parent.parent assert (CHECKOUT / "configure").is_file(), ( "Please update the location of the file" @@ -28,9 +27,9 @@ LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" LOCAL_SETUP_MARKER = ( - "# Generated by Tools/wasm/wasi .\n" - "# Required to statically build extension modules." -).encode("utf-8") + b"# Generated by Tools/wasm/wasi .\n" + b"# Required to statically build extension modules." +) WASI_SDK_VERSION = 24 @@ -154,8 +153,7 @@ def build_python_is_pydebug(): test = "import sys, test.support; sys.exit(test.support.Py_DEBUG)" result = subprocess.run( [build_python_path(), "-c", test], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, ) return bool(result.returncode) From c3784427fc7a129e3c52683010b38308ce635f4e Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:22:35 +0300 Subject: [PATCH 2/4] Lint fixes --- Tools/wasm/wasm_build.py | 84 +++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 45 deletions(-) diff --git a/Tools/wasm/wasm_build.py b/Tools/wasm/wasm_build.py index 73875a2205e6a8..6f33c4fd6c4f95 100755 --- a/Tools/wasm/wasm_build.py +++ b/Tools/wasm/wasm_build.py @@ -23,8 +23,8 @@ """ import argparse -import enum import dataclasses +import enum import logging import os import pathlib @@ -39,18 +39,12 @@ 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 @@ 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 @@ def get_extra_paths(self) -> Iterable[pathlib.PurePath]: 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 @@ def emport_args(self) -> List[str]: 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 @@ def is_browser(self) -> bool: 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 @@ def makefile(self) -> pathlib.Path: 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 @@ def configure_cmd(self) -> List[str]: 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 @@ def make_cmd(self) -> List[str]: 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 @@ def getenv(self) -> Dict[str, Any]: 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 @@ def _run_cmd( 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 @@ def run_pythoninfo(self, *args: str) -> int: 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,8 +817,8 @@ def build_emports(self, force: bool = False) -> None: ) # 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) + [ +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( @@ -834,18 +828,18 @@ def build_emports(self, force: bool = False) -> None: 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", From 881e99454a0d68e018a00ff8c85a126fe808b0ab Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:23:04 +0300 Subject: [PATCH 3/4] Format fix --- Tools/wasm/wasm_build.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Tools/wasm/wasm_build.py b/Tools/wasm/wasm_build.py index 6f33c4fd6c4f95..3f1bde3853fce7 100755 --- a/Tools/wasm/wasm_build.py +++ b/Tools/wasm/wasm_build.py @@ -818,9 +818,7 @@ def build_emports(self, force: bool = False) -> None: # Don't list broken and experimental variants in help platforms_choices = [p.name for p in _profiles] + ["cleanall"] -platforms_help = [p.name for p in _profiles if p.support_level] + [ - "cleanall" -] +platforms_help = [p.name for p in _profiles if p.support_level] + ["cleanall"] parser.add_argument( "platform", metavar="PLATFORM", From 5212b387d02e6c4be037a9a0a00edcbfa9994ec5 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:40:43 +0300 Subject: [PATCH 4/4] Delete Tools/wasm/mypy.ini --- .github/workflows/mypy.yml | 2 -- Tools/wasm/mypy.ini | 11 ----------- 2 files changed, 13 deletions(-) delete mode 100644 Tools/wasm/mypy.ini diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 498a7d0a844110..5d5d77f29f6eb1 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -29,7 +29,6 @@ on: - "Tools/jit/**" - "Tools/peg_generator/**" - "Tools/requirements-dev.txt" - - "Tools/wasm/**" workflow_dispatch: permissions: @@ -61,7 +60,6 @@ jobs: "Tools/clinic", "Tools/jit", "Tools/peg_generator", - "Tools/wasm", ] steps: - uses: actions/checkout@v4 diff --git a/Tools/wasm/mypy.ini b/Tools/wasm/mypy.ini deleted file mode 100644 index 4de0a30c260f5f..00000000000000 --- 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