Skip to content

Commit 00ecd77

Browse files
committed
pythongh-109125: Run mypy on Tools/wasm
1 parent 00cf626 commit 00ecd77

File tree

5 files changed

+68
-38
lines changed

5 files changed

+68
-38
lines changed

.github/workflows/mypy.yml

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ jobs:
3434
"Tools/cases_generator",
3535
"Tools/clinic",
3636
"Tools/peg_generator",
37+
"Tools/wasm",
3738
]
3839
name: Run mypy on ${{ matrix.target }}
3940
runs-on: ubuntu-latest

Tools/wasm/mypy.ini

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[mypy]
2+
files = Tools/wasm
3+
pretty = True
4+
show_traceback = True
5+
6+
# Make sure the wasm can be run using Python 3.8:
7+
python_version = 3.8
8+
9+
# Be strict...
10+
strict = True
11+
enable_error_code = truthy-bool,ignore-without-code
12+
13+
# except for a few settings that can't yet be enabled:
14+
warn_return_any = False
15+
warn_unreachable = False

Tools/wasm/wasm_assets.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import sys
1717
import sysconfig
1818
import zipfile
19+
from typing import Dict
1920

2021
# source directory
2122
SRCDIR = pathlib.Path(__file__).parent.parent.parent.absolute()
@@ -110,7 +111,7 @@ def get_builddir(args: argparse.Namespace) -> pathlib.Path:
110111

111112
def get_sysconfigdata(args: argparse.Namespace) -> pathlib.Path:
112113
"""Get path to sysconfigdata relative to build root"""
113-
data_name = sysconfig._get_sysconfigdata_name()
114+
data_name = sysconfig._get_sysconfigdata_name() # type: ignore[attr-defined]
114115
if not data_name.startswith(SYSCONFIG_NAMES):
115116
raise ValueError(
116117
f"Invalid sysconfig data name '{data_name}'.", SYSCONFIG_NAMES
@@ -146,7 +147,7 @@ def filterfunc(filename: str) -> bool:
146147
pzf.writepy(entry, filterfunc=filterfunc)
147148

148149

149-
def detect_extension_modules(args: argparse.Namespace):
150+
def detect_extension_modules(args: argparse.Namespace) -> Dict[str, bool]:
150151
modules = {}
151152

152153
# disabled by Modules/Setup.local ?
@@ -161,7 +162,7 @@ def detect_extension_modules(args: argparse.Namespace):
161162
# disabled by configure?
162163
with open(args.sysconfig_data) as f:
163164
data = f.read()
164-
loc = {}
165+
loc: Dict[str, Dict[str, str]] = {}
165166
exec(data, globals(), loc)
166167

167168
for key, value in loc["build_time_vars"].items():
@@ -195,7 +196,7 @@ def path(val: str) -> pathlib.Path:
195196
)
196197

197198

198-
def main():
199+
def main() -> None:
199200
args = parser.parse_args()
200201

201202
relative_prefix = args.prefix.relative_to(pathlib.Path("/"))

Tools/wasm/wasm_build.py

+43-30
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,17 @@
4040
import webbrowser
4141

4242
# for Python 3.8
43-
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
43+
from typing import (
44+
cast,
45+
Any,
46+
Callable,
47+
Dict,
48+
Iterable,
49+
List,
50+
Optional,
51+
Tuple,
52+
Union,
53+
)
4454

4555
logger = logging.getLogger("wasm_build")
4656

@@ -64,7 +74,7 @@
6474
(3, 1, 16): "https://github.com/emscripten-core/emscripten/issues/17393",
6575
(3, 1, 20): "https://github.com/emscripten-core/emscripten/issues/17720",
6676
}
67-
_MISSING = pathlib.PurePath("MISSING")
77+
_MISSING = pathlib.Path("MISSING")
6878

6979
WASM_WEBSERVER = WASMTOOLS / "wasm_webserver.py"
7080

@@ -109,7 +119,7 @@
109119

110120
def parse_emconfig(
111121
emconfig: pathlib.Path = EM_CONFIG,
112-
) -> Tuple[pathlib.PurePath, pathlib.PurePath]:
122+
) -> Tuple[pathlib.Path, pathlib.Path]:
113123
"""Parse EM_CONFIG file and lookup EMSCRIPTEN_ROOT and NODE_JS.
114124
115125
The ".emscripten" config file is a Python snippet that uses "EM_CONFIG"
@@ -150,11 +160,11 @@ def read_python_version(configure: pathlib.Path = CONFIGURE) -> str:
150160

151161

152162
class ConditionError(ValueError):
153-
def __init__(self, info: str, text: str):
163+
def __init__(self, info: str, text: str) -> None:
154164
self.info = info
155165
self.text = text
156166

157-
def __str__(self):
167+
def __str__(self) -> str:
158168
return f"{type(self).__name__}: '{self.info}'\n{self.text}"
159169

160170

@@ -180,19 +190,19 @@ class Platform:
180190
name: str
181191
pythonexe: str
182192
config_site: Optional[pathlib.PurePath]
183-
configure_wrapper: Optional[pathlib.PurePath]
193+
configure_wrapper: Optional[pathlib.Path]
184194
make_wrapper: Optional[pathlib.PurePath]
185-
environ: dict
195+
environ: Dict[str, Any]
186196
check: Callable[[], None]
187197
# Used for build_emports().
188198
ports: Optional[pathlib.PurePath]
189199
cc: Optional[pathlib.PurePath]
190200

191-
def getenv(self, profile: "BuildProfile") -> dict:
201+
def getenv(self, profile: "BuildProfile") -> Dict[str, Any]:
192202
return self.environ.copy()
193203

194204

195-
def _check_clean_src():
205+
def _check_clean_src() -> None:
196206
candidates = [
197207
SRCDIR / "Programs" / "python.o",
198208
SRCDIR / "Python" / "frozen_modules" / "importlib._bootstrap.h",
@@ -202,7 +212,7 @@ def _check_clean_src():
202212
raise DirtySourceDirectory(os.fspath(candidate), CLEAN_SRCDIR)
203213

204214

205-
def _check_native():
215+
def _check_native() -> None:
206216
if not any(shutil.which(cc) for cc in ["cc", "gcc", "clang"]):
207217
raise MissingDependency("cc", INSTALL_NATIVE)
208218
if not shutil.which("make"):
@@ -234,12 +244,12 @@ def _check_native():
234244
)
235245

236246

237-
def _check_emscripten():
247+
def _check_emscripten() -> None:
238248
if EMSCRIPTEN_ROOT is _MISSING:
239249
raise MissingDependency("Emscripten SDK EM_CONFIG", INSTALL_EMSDK)
240250
# sanity check
241251
emconfigure = EMSCRIPTEN.configure_wrapper
242-
if not emconfigure.exists():
252+
if emconfigure is not None and not emconfigure.exists():
243253
raise MissingDependency(os.fspath(emconfigure), INSTALL_EMSDK)
244254
# version check
245255
version_txt = EMSCRIPTEN_ROOT / "emscripten-version.txt"
@@ -250,7 +260,10 @@ def _check_emscripten():
250260
if version.endswith("-git"):
251261
# git / upstream / tot-upstream installation
252262
version = version[:-4]
253-
version_tuple = tuple(int(v) for v in version.split("."))
263+
version_tuple = cast(
264+
Tuple[int, int, int],
265+
tuple(int(v) for v in version.split("."))
266+
)
254267
if version_tuple < EMSDK_MIN_VERSION:
255268
raise ConditionError(
256269
os.fspath(version_txt),
@@ -293,7 +306,7 @@ def _check_emscripten():
293306
)
294307

295308

296-
def _check_wasi():
309+
def _check_wasi() -> None:
297310
wasm_ld = WASI_SDK_PATH / "bin" / "wasm-ld"
298311
if not wasm_ld.exists():
299312
raise MissingDependency(os.fspath(wasm_ld), INSTALL_WASI_SDK)
@@ -400,7 +413,7 @@ class EmscriptenTarget(enum.Enum):
400413
node_debug = "node-debug"
401414

402415
@property
403-
def is_browser(self):
416+
def is_browser(self) -> bool:
404417
cls = type(self)
405418
return self in {cls.browser, cls.browser_debug}
406419

@@ -421,7 +434,7 @@ class SupportLevel(enum.Enum):
421434
experimental = "experimental, may be broken"
422435
broken = "broken / unavailable"
423436

424-
def __bool__(self):
437+
def __bool__(self) -> bool:
425438
cls = type(self)
426439
return self in {cls.supported, cls.working}
427440

@@ -500,7 +513,7 @@ def make_cmd(self) -> List[str]:
500513
cmd.insert(0, os.fspath(platform.make_wrapper))
501514
return cmd
502515

503-
def getenv(self) -> dict:
516+
def getenv(self) -> Dict[str, Any]:
504517
"""Generate environ dict for platform"""
505518
env = os.environ.copy()
506519
env.setdefault("MAKEFLAGS", f"-j{os.cpu_count()}")
@@ -529,7 +542,7 @@ def _run_cmd(
529542
cmd: Iterable[str],
530543
args: Iterable[str] = (),
531544
cwd: Optional[pathlib.Path] = None,
532-
):
545+
) -> int:
533546
cmd = list(cmd)
534547
cmd.extend(args)
535548
if cwd is None:
@@ -541,46 +554,46 @@ def _run_cmd(
541554
env=self.getenv(),
542555
)
543556

544-
def _check_execute(self):
557+
def _check_execute(self) -> None:
545558
if self.is_browser:
546559
raise ValueError(f"Cannot execute on {self.target}")
547560

548-
def run_build(self, *args):
561+
def run_build(self, *args: str) -> None:
549562
"""Run configure (if necessary) and make"""
550563
if not self.makefile.exists():
551564
logger.info("Makefile not found, running configure")
552565
self.run_configure(*args)
553566
self.run_make("all", *args)
554567

555-
def run_configure(self, *args):
568+
def run_configure(self, *args: str) -> int:
556569
"""Run configure script to generate Makefile"""
557570
os.makedirs(self.builddir, exist_ok=True)
558571
return self._run_cmd(self.configure_cmd, args)
559572

560-
def run_make(self, *args):
573+
def run_make(self, *args: str) -> int:
561574
"""Run make (defaults to build all)"""
562575
return self._run_cmd(self.make_cmd, args)
563576

564-
def run_pythoninfo(self, *args):
577+
def run_pythoninfo(self, *args: str) -> int:
565578
"""Run 'make pythoninfo'"""
566579
self._check_execute()
567580
return self.run_make("pythoninfo", *args)
568581

569-
def run_test(self, target: str, testopts: Optional[str] = None):
582+
def run_test(self, target: str, testopts: Optional[str] = None) -> int:
570583
"""Run buildbottests"""
571584
self._check_execute()
572585
if testopts is None:
573586
testopts = self.default_testopts
574587
return self.run_make(target, f"TESTOPTS={testopts}")
575588

576-
def run_py(self, *args):
589+
def run_py(self, *args: str) -> int:
577590
"""Run Python with hostrunner"""
578591
self._check_execute()
579-
self.run_make(
592+
return self.run_make(
580593
"--eval", f"run: all; $(HOSTRUNNER) ./$(PYTHON) {shlex.join(args)}", "run"
581594
)
582595

583-
def run_browser(self, bind="127.0.0.1", port=8000):
596+
def run_browser(self, bind: str = "127.0.0.1", port: int = 8000) -> None:
584597
"""Run WASM webserver and open build in browser"""
585598
relbuilddir = self.builddir.relative_to(SRCDIR)
586599
url = f"http://{bind}:{port}/{relbuilddir}/python.html"
@@ -611,15 +624,15 @@ def run_browser(self, bind="127.0.0.1", port=8000):
611624
except KeyboardInterrupt:
612625
pass
613626

614-
def clean(self, all: bool = False):
627+
def clean(self, all: bool = False) -> None:
615628
"""Clean build directory"""
616629
if all:
617630
if self.builddir.exists():
618631
shutil.rmtree(self.builddir)
619632
elif self.makefile.exists():
620633
self.run_make("clean")
621634

622-
def build_emports(self, force: bool = False):
635+
def build_emports(self, force: bool = False) -> None:
623636
"""Pre-build emscripten ports."""
624637
platform = self.host.platform
625638
if platform.ports is None or platform.cc is None:
@@ -829,7 +842,7 @@ def build_emports(self, force: bool = False):
829842
)
830843

831844

832-
def main():
845+
def main() -> None:
833846
args = parser.parse_args()
834847
logging.basicConfig(
835848
level=logging.INFO if args.verbose else logging.ERROR,

Tools/wasm/wasm_webserver.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,21 @@ class MyHTTPRequestHandler(server.SimpleHTTPRequestHandler):
2121
}
2222
)
2323

24-
def end_headers(self):
24+
def end_headers(self) -> None:
2525
self.send_my_headers()
2626
super().end_headers()
2727

28-
def send_my_headers(self):
28+
def send_my_headers(self) -> None:
2929
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
3030
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
3131

3232

33-
def main():
33+
def main() -> None:
3434
args = parser.parse_args()
3535
if not args.bind:
3636
args.bind = None
3737

38-
server.test(
38+
server.test( # type: ignore[attr-defined]
3939
HandlerClass=MyHTTPRequestHandler,
4040
protocol="HTTP/1.1",
4141
port=args.port,

0 commit comments

Comments
 (0)