-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
gh-109413: Add a custom script for running mypy on libregrtest #109464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
import types | ||
import unittest | ||
import warnings | ||
from collections.abc import Callable | ||
|
||
from .testresult import get_test_runner | ||
|
||
|
@@ -183,12 +184,12 @@ def get_attribute(obj, name): | |
else: | ||
return attribute | ||
|
||
verbose = 1 # Flag set to 0 by regrtest.py | ||
use_resources = None # Flag set to [] by regrtest.py | ||
max_memuse = 0 # Disable bigmem tests (they will still be run with | ||
# small sizes, to make sure they work.) | ||
verbose = 1 # Flag set to 0 by regrtest.py | ||
use_resources: tuple[str, ...] | None = None # Flag set to a tuple by regrtest.py | ||
max_memuse = 0 # Disable bigmem tests (they will still be run with | ||
# small sizes, to make sure they work.) | ||
real_max_memuse = 0 | ||
junit_xml_list = None # list of testsuite XML elements | ||
junit_xml_list: list | None = None # list of testsuite XML elements | ||
failfast = False | ||
|
||
# _original_stdout is meant to hold stdout at the time regrtest began. | ||
|
@@ -1325,6 +1326,18 @@ def flush_std_streams(): | |
sys.stderr.flush() | ||
|
||
|
||
class WarningsPrinter: | ||
def __init__(self, func: Callable[[str], None]) -> None: | ||
self.func = func | ||
# bpo-39983: Store the original sys.stderr at Python startup to be able to | ||
# log warnings even if sys.stderr is captured temporarily by a test. | ||
self.orig_stderr = sys.stderr | ||
|
||
def __call__(self, msg: str) -> None: | ||
return self.func(msg) | ||
|
||
|
||
@WarningsPrinter | ||
Comment on lines
+1329
to
+1340
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mypy doesn't like assigning attributes to functions, unfortunately; it much prefers the idea of a custom callable class There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (This is the solution you said you preferred in #109382 (comment) :-) |
||
def print_warning(msg): | ||
# bpo-45410: Explicitly flush stdout to keep logs in order | ||
flush_std_streams() | ||
|
@@ -1333,10 +1346,6 @@ def print_warning(msg): | |
print(f"Warning -- {line}", file=stream) | ||
stream.flush() | ||
|
||
# bpo-39983: Store the original sys.stderr at Python startup to be able to | ||
# log warnings even if sys.stderr is captured temporarily by a test. | ||
print_warning.orig_stderr = sys.stderr | ||
|
||
|
||
# Flag used by saved_test_environment of test.libregrtest.save_env, | ||
# to check if a test modified the environment. The flag should be set to False | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
""" | ||
Script to run mypy on Lib/test/libregrtest. | ||
|
||
This script is necessary due to the fact that, | ||
if you invoke mypy directly on anything inside the Lib/ directory, | ||
it (amusingly) thinks that everything in the stdlib is being "shadowed" | ||
by the modules inside `Lib/`. | ||
""" | ||
|
||
import argparse | ||
import os | ||
import shutil | ||
import subprocess | ||
import tempfile | ||
from pathlib import Path | ||
from typing import TypeAlias | ||
|
||
ReturnCode: TypeAlias = int | ||
|
||
|
||
def run_mypy_on_libregrtest(root_dir: Path) -> ReturnCode: | ||
test_dot_support_dir = root_dir / "Lib/" / "test" / "support" | ||
# Copy `Lib/test/support/` into a tempdir and point MYPYPATH towards the tempdir, | ||
# so that mypy can see the classes and functions defined in `Lib/test/support/` | ||
with tempfile.TemporaryDirectory() as td: | ||
td_path = Path(td) | ||
(td_path / "test").mkdir() | ||
shutil.copytree(test_dot_support_dir, td_path / "test" / "support") | ||
mypy_command = [ | ||
"mypy", | ||
"--config-file", | ||
"Lib/test/libregrtest/mypy.ini", | ||
] | ||
result = subprocess.run( | ||
mypy_command, cwd=root_dir, env=os.environ | {"MYPYPATH": td} | ||
) | ||
return result.returncode | ||
|
||
|
||
def main() -> ReturnCode: | ||
parser = argparse.ArgumentParser("Script to run mypy on Lib/test/regrtest/") | ||
parser.add_argument( | ||
"--root-dir", | ||
"-r", | ||
type=Path, | ||
required=True, | ||
help="path to the CPython repo root", | ||
) | ||
args = parser.parse_args() | ||
root_dir = args.root_dir | ||
test_dot_support_dir = root_dir / "Lib" / "test" / "support" | ||
if not (test_dot_support_dir.exists() and test_dot_support_dir.is_dir()): | ||
parser.error("--root-dir must point to the root of a CPython clone!") | ||
return run_mypy_on_libregrtest(root_dir) | ||
|
||
|
||
if __name__ == "__main__": | ||
raise SystemExit(main()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revealing the existence of this module to mypy necessitated fixing a few typing-related things to do with this module