[3.14] gh-139590: Stricter ruff rules for Tools/wasm (GH-139752) (#139811)

Co-authored-by: sobolevn <mail@sobolevn.me>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot) 2025-10-14 09:29:32 +02:00 committed by GitHub
parent 7a13953bc3
commit 5848d80536
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 53 additions and 77 deletions

View file

@ -29,7 +29,6 @@ on:
- "Tools/jit/**" - "Tools/jit/**"
- "Tools/peg_generator/**" - "Tools/peg_generator/**"
- "Tools/requirements-dev.txt" - "Tools/requirements-dev.txt"
- "Tools/wasm/**"
workflow_dispatch: workflow_dispatch:
permissions: permissions:
@ -61,7 +60,6 @@ jobs:
"Tools/clinic", "Tools/clinic",
"Tools/jit", "Tools/jit",
"Tools/peg_generator", "Tools/peg_generator",
"Tools/wasm",
] ]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View file

@ -26,6 +26,10 @@ repos:
name: Run Ruff (lint) on Tools/peg_generator/ name: Run Ruff (lint) on Tools/peg_generator/
args: [--exit-non-zero-on-fix, --config=Tools/peg_generator/.ruff.toml] args: [--exit-non-zero-on-fix, --config=Tools/peg_generator/.ruff.toml]
files: ^Tools/peg_generator/ 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 - id: ruff-format
name: Run Ruff (format) on Doc/ name: Run Ruff (format) on Doc/
args: [--check] args: [--check]

View file

@ -22,7 +22,4 @@ select = [
] ]
ignore = [ ignore = [
"E501", # Line too long "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`
] ]

View file

@ -3,16 +3,16 @@
import argparse import argparse
import contextlib import contextlib
import functools import functools
import hashlib
import os import os
import shutil import shutil
import subprocess import subprocess
import sys import sys
import sysconfig import sysconfig
import hashlib
import tempfile import tempfile
from urllib.request import urlopen
from pathlib import Path from pathlib import Path
from textwrap import dedent from textwrap import dedent
from urllib.request import urlopen
try: try:
from os import process_cpu_count as cpu_count from os import process_cpu_count as cpu_count
@ -33,9 +33,7 @@ HOST_DIR = HOST_BUILD_DIR / "python"
PREFIX_DIR = CROSS_BUILD_DIR / HOST_TRIPLE / "prefix" PREFIX_DIR = CROSS_BUILD_DIR / HOST_TRIPLE / "prefix"
LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local"
LOCAL_SETUP_MARKER = "# Generated by Tools/wasm/emscripten.py\n".encode( LOCAL_SETUP_MARKER = b"# Generated by Tools/wasm/emscripten.py\n"
"utf-8"
)
def updated_env(updates={}): def updated_env(updates={}):
@ -432,6 +430,7 @@ def main():
make_build, make_build,
configure_host, configure_host,
make_host, make_host,
clean,
): ):
subcommand.add_argument( subcommand.add_argument(
"--quiet", "--quiet",

View file

@ -15,7 +15,6 @@ import pathlib
import sys import sys
import sysconfig import sysconfig
import zipfile import zipfile
from typing import Dict
# source directory # source directory
SRCDIR = pathlib.Path(__file__).parents[3].absolute() SRCDIR = pathlib.Path(__file__).parents[3].absolute()
@ -134,7 +133,7 @@ def create_stdlib_zip(
pzf.writepy(entry, filterfunc=filterfunc) 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 = {} modules = {}
# disabled by Modules/Setup.local ? # disabled by Modules/Setup.local ?
@ -149,7 +148,7 @@ def detect_extension_modules(args: argparse.Namespace) -> Dict[str, bool]:
# disabled by configure? # disabled by configure?
with open(args.sysconfig_data) as f: with open(args.sysconfig_data) as f:
data = f.read() data = f.read()
loc: Dict[str, Dict[str, str]] = {} loc: dict[str, dict[str, str]] = {}
exec(data, globals(), loc) exec(data, globals(), loc)
for key, value in loc["build_time_vars"].items(): for key, value in loc["build_time_vars"].items():

View file

@ -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

View file

@ -16,7 +16,6 @@ import sys
import sysconfig import sysconfig
import tempfile import tempfile
CHECKOUT = pathlib.Path(__file__).parent.parent.parent.parent CHECKOUT = pathlib.Path(__file__).parent.parent.parent.parent
assert (CHECKOUT / "configure").is_file(), ( assert (CHECKOUT / "configure").is_file(), (
"Please update the location of the file" "Please update the location of the file"
@ -28,9 +27,9 @@ BUILD_DIR = CROSS_BUILD_DIR / sysconfig.get_config_var("BUILD_GNU_TYPE")
LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local"
LOCAL_SETUP_MARKER = ( LOCAL_SETUP_MARKER = (
"# Generated by Tools/wasm/wasi .\n" b"# Generated by Tools/wasm/wasi .\n"
"# Required to statically build extension modules." b"# Required to statically build extension modules."
).encode("utf-8") )
WASI_SDK_VERSION = 24 WASI_SDK_VERSION = 24
@ -154,8 +153,7 @@ def build_python_is_pydebug():
test = "import sys, test.support; sys.exit(test.support.Py_DEBUG)" test = "import sys, test.support; sys.exit(test.support.Py_DEBUG)"
result = subprocess.run( result = subprocess.run(
[build_python_path(), "-c", test], [build_python_path(), "-c", test],
stdout=subprocess.PIPE, capture_output=True,
stderr=subprocess.PIPE,
) )
return bool(result.returncode) return bool(result.returncode)

View file

@ -23,8 +23,8 @@ changes.
""" """
import argparse import argparse
import enum
import dataclasses import dataclasses
import enum
import logging import logging
import os import os
import pathlib import pathlib
@ -39,18 +39,12 @@ import tempfile
import time import time
import warnings import warnings
import webbrowser import webbrowser
from collections.abc import Callable, Iterable
# for Python 3.8 # for Python 3.8
from typing import ( from typing import (
cast,
Any, Any,
Callable, cast,
Dict,
Iterable,
List,
Optional,
Tuple,
Union,
) )
logger = logging.getLogger("wasm_build") logger = logging.getLogger("wasm_build")
@ -122,7 +116,7 @@ https://wasmtime.dev/ to install wasmtime.
def parse_emconfig( def parse_emconfig(
emconfig: pathlib.Path = EM_CONFIG, 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. """Parse EM_CONFIG file and lookup EMSCRIPTEN_ROOT and NODE_JS.
The ".emscripten" config file is a Python snippet that uses "EM_CONFIG" 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: with open(emconfig, encoding="utf-8") as f:
code = f.read() code = f.read()
# EM_CONFIG file is a Python snippet # EM_CONFIG file is a Python snippet
local: Dict[str, Any] = {} local: dict[str, Any] = {}
exec(code, globals(), local) exec(code, globals(), local)
emscripten_root = pathlib.Path(local["EMSCRIPTEN_ROOT"]) emscripten_root = pathlib.Path(local["EMSCRIPTEN_ROOT"])
node_js = pathlib.Path(local["NODE_JS"]) node_js = pathlib.Path(local["NODE_JS"])
@ -192,16 +186,16 @@ class Platform:
name: str name: str
pythonexe: str pythonexe: str
config_site: Optional[pathlib.PurePath] config_site: pathlib.PurePath | None
configure_wrapper: Optional[pathlib.Path] configure_wrapper: pathlib.Path | None
make_wrapper: Optional[pathlib.PurePath] make_wrapper: pathlib.PurePath | None
environ: Dict[str, Any] environ: dict[str, Any]
check: Callable[[], None] check: Callable[[], None]
# Used for build_emports(). # Used for build_emports().
ports: Optional[pathlib.PurePath] ports: pathlib.PurePath | None
cc: Optional[pathlib.PurePath] cc: pathlib.PurePath | None
def getenv(self, profile: "BuildProfile") -> Dict[str, Any]: def getenv(self, profile: "BuildProfile") -> dict[str, Any]:
return self.environ.copy() return self.environ.copy()
@ -264,7 +258,7 @@ def _check_emscripten() -> None:
# git / upstream / tot-upstream installation # git / upstream / tot-upstream installation
version = version[:-4] version = version[:-4]
version_tuple = cast( 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: if version_tuple < EMSDK_MIN_VERSION:
raise ConditionError( raise ConditionError(
@ -388,7 +382,7 @@ class Host(enum.Enum):
return [] return []
@property @property
def emport_args(self) -> List[str]: def emport_args(self) -> list[str]:
"""Host-specific port args (Emscripten).""" """Host-specific port args (Emscripten)."""
cls = type(self) cls = type(self)
if self is cls.wasm64_emscripten: if self is cls.wasm64_emscripten:
@ -399,7 +393,7 @@ class Host(enum.Enum):
return [] return []
@property @property
def embuilder_args(self) -> List[str]: def embuilder_args(self) -> list[str]:
"""Host-specific embuilder args (Emscripten).""" """Host-specific embuilder args (Emscripten)."""
cls = type(self) cls = type(self)
if self is cls.wasm64_emscripten: if self is cls.wasm64_emscripten:
@ -422,7 +416,7 @@ class EmscriptenTarget(enum.Enum):
return self in {cls.browser, cls.browser_debug} return self in {cls.browser, cls.browser_debug}
@property @property
def emport_args(self) -> List[str]: def emport_args(self) -> list[str]:
"""Target-specific port args.""" """Target-specific port args."""
cls = type(self) cls = type(self)
if self in {cls.browser_debug, cls.node_debug}: if self in {cls.browser_debug, cls.node_debug}:
@ -448,9 +442,9 @@ class BuildProfile:
name: str name: str
support_level: SupportLevel support_level: SupportLevel
host: Host host: Host
target: Union[EmscriptenTarget, None] = None target: EmscriptenTarget | None = None
dynamic_linking: Union[bool, None] = None dynamic_linking: bool | None = None
pthreads: Union[bool, None] = None pthreads: bool | None = None
default_testopts: str = "-j2" default_testopts: str = "-j2"
@property @property
@ -474,7 +468,7 @@ class BuildProfile:
return self.builddir / "Makefile" return self.builddir / "Makefile"
@property @property
def configure_cmd(self) -> List[str]: def configure_cmd(self) -> list[str]:
"""Generate configure command""" """Generate configure command"""
# use relative path, so WASI tests can find lib prefix. # use relative path, so WASI tests can find lib prefix.
# pathlib.Path.relative_to() does not work here. # pathlib.Path.relative_to() does not work here.
@ -509,7 +503,7 @@ class BuildProfile:
return cmd return cmd
@property @property
def make_cmd(self) -> List[str]: def make_cmd(self) -> list[str]:
"""Generate make command""" """Generate make command"""
cmd = ["make"] cmd = ["make"]
platform = self.host.platform platform = self.host.platform
@ -517,7 +511,7 @@ class BuildProfile:
cmd.insert(0, os.fspath(platform.make_wrapper)) cmd.insert(0, os.fspath(platform.make_wrapper))
return cmd return cmd
def getenv(self) -> Dict[str, Any]: def getenv(self) -> dict[str, Any]:
"""Generate environ dict for platform""" """Generate environ dict for platform"""
env = os.environ.copy() env = os.environ.copy()
if hasattr(os, "process_cpu_count"): if hasattr(os, "process_cpu_count"):
@ -531,7 +525,7 @@ class BuildProfile:
env.pop(key, None) env.pop(key, None)
elif key == "PATH": elif key == "PATH":
# list of path items, prefix with extra paths # 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(self.host.get_extra_paths())
new_path.extend(value) new_path.extend(value)
env[key] = os.pathsep.join(os.fspath(p) for p in new_path) env[key] = os.pathsep.join(os.fspath(p) for p in new_path)
@ -549,7 +543,7 @@ class BuildProfile:
self, self,
cmd: Iterable[str], cmd: Iterable[str],
args: Iterable[str] = (), args: Iterable[str] = (),
cwd: Optional[pathlib.Path] = None, cwd: pathlib.Path | None = None,
) -> int: ) -> int:
cmd = list(cmd) cmd = list(cmd)
cmd.extend(args) cmd.extend(args)
@ -587,7 +581,7 @@ class BuildProfile:
self._check_execute() self._check_execute()
return self.run_make("pythoninfo", *args) 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""" """Run buildbottests"""
self._check_execute() self._check_execute()
if testopts is None: if testopts is None:
@ -823,10 +817,8 @@ parser.add_argument(
) )
# Don't list broken and experimental variants in help # Don't list broken and experimental variants in help
platforms_choices = list(p.name for p in _profiles) + ["cleanall"] platforms_choices = [p.name for p in _profiles] + ["cleanall"]
platforms_help = list(p.name for p in _profiles if p.support_level) + [ platforms_help = [p.name for p in _profiles if p.support_level] + ["cleanall"]
"cleanall"
]
parser.add_argument( parser.add_argument(
"platform", "platform",
metavar="PLATFORM", metavar="PLATFORM",
@ -834,18 +826,18 @@ parser.add_argument(
choices=platforms_choices, choices=platforms_choices,
) )
ops = dict( ops = {
build="auto build (build 'build' Python, emports, configure, compile)", "build": "auto build (build 'build' Python, emports, configure, compile)",
configure="run ./configure", "configure": "run ./configure",
compile="run 'make all'", "compile": "run 'make all'",
pythoninfo="run 'make pythoninfo'", "pythoninfo": "run 'make pythoninfo'",
test="run 'make buildbottest TESTOPTS=...' (supports parallel tests)", "test": "run 'make buildbottest TESTOPTS=...' (supports parallel tests)",
hostrunnertest="run 'make hostrunnertest TESTOPTS=...'", "hostrunnertest": "run 'make hostrunnertest TESTOPTS=...'",
repl="start interactive REPL / webserver + browser session", "repl": "start interactive REPL / webserver + browser session",
clean="run 'make clean'", "clean": "run 'make clean'",
cleanall="remove all build directories", "cleanall": "remove all build directories",
emports="build Emscripten port with embuilder (only Emscripten)", "emports": "build Emscripten port with embuilder (only Emscripten)",
) }
ops_help = "\n".join(f"{op:16s} {help}" for op, help in ops.items()) ops_help = "\n".join(f"{op:16s} {help}" for op, help in ops.items())
parser.add_argument( parser.add_argument(
"ops", "ops",