Skip to content

Commit 3b9d10b

Browse files
authored
gh-109413: libregrtest: Add and improve type annotations (#109405)
1 parent 21e80f4 commit 3b9d10b

13 files changed

+83
-33
lines changed

Lib/test/libregrtest/cmdline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def __init__(self, **kwargs) -> None:
161161
self.trace = False
162162
self.coverdir = 'coverage'
163163
self.runleaks = False
164-
self.huntrleaks = False
164+
self.huntrleaks: tuple[int, int, str] | None = None
165165
self.rerun = False
166166
self.verbose3 = False
167167
self.print_slow = False

Lib/test/libregrtest/findtests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
}
2525

2626

27-
def findtestdir(path=None):
27+
def findtestdir(path: StrPath | None = None) -> StrPath:
2828
return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir
2929

3030

Lib/test/libregrtest/logger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def __init__(self, results: TestResults, quiet: bool, pgo: bool):
1414
self.start_time = time.perf_counter()
1515
self.test_count_text = ''
1616
self.test_count_width = 3
17-
self.win_load_tracker = None
17+
self.win_load_tracker: WindowsLoadTracker | None = None
1818
self._results: TestResults = results
1919
self._quiet: bool = quiet
2020
self._pgo: bool = pgo

Lib/test/libregrtest/main.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ def __init__(self, ns: Namespace):
7171

7272
# Select tests
7373
if ns.match_tests:
74-
self.match_tests: FilterTuple = tuple(ns.match_tests)
74+
self.match_tests: FilterTuple | None = tuple(ns.match_tests)
7575
else:
7676
self.match_tests = None
7777
if ns.ignore_tests:
78-
self.ignore_tests: FilterTuple = tuple(ns.ignore_tests)
78+
self.ignore_tests: FilterTuple | None = tuple(ns.ignore_tests)
7979
else:
8080
self.ignore_tests = None
8181
self.exclude: bool = ns.exclude
@@ -105,16 +105,16 @@ def __init__(self, ns: Namespace):
105105
if ns.huntrleaks:
106106
warmups, runs, filename = ns.huntrleaks
107107
filename = os.path.abspath(filename)
108-
self.hunt_refleak: HuntRefleak = HuntRefleak(warmups, runs, filename)
108+
self.hunt_refleak: HuntRefleak | None = HuntRefleak(warmups, runs, filename)
109109
else:
110110
self.hunt_refleak = None
111111
self.test_dir: StrPath | None = ns.testdir
112112
self.junit_filename: StrPath | None = ns.xmlpath
113113
self.memory_limit: str | None = ns.memlimit
114114
self.gc_threshold: int | None = ns.threshold
115-
self.use_resources: tuple[str] = tuple(ns.use_resources)
115+
self.use_resources: tuple[str, ...] = tuple(ns.use_resources)
116116
if ns.python:
117-
self.python_cmd: tuple[str] = tuple(ns.python)
117+
self.python_cmd: tuple[str, ...] | None = tuple(ns.python)
118118
else:
119119
self.python_cmd = None
120120
self.coverage: bool = ns.trace
@@ -389,7 +389,7 @@ def create_run_tests(self, tests: TestTuple):
389389
match_tests=self.match_tests,
390390
ignore_tests=self.ignore_tests,
391391
match_tests_dict=None,
392-
rerun=None,
392+
rerun=False,
393393
forever=self.forever,
394394
pgo=self.pgo,
395395
pgo_extended=self.pgo_extended,

Lib/test/libregrtest/mypy.ini

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Config file for running mypy on libregrtest.
2+
#
3+
# Note: mypy can't be run on libregrtest from the CPython repo root.
4+
# If you try to do so, mypy will complain
5+
# about the entire `Lib/` directory "shadowing the stdlib".
6+
# Instead, `cd` into `Lib/test`, then run `mypy --config-file libregrtest/mypy.ini`.
7+
8+
[mypy]
9+
packages = libregrtest
10+
python_version = 3.11
11+
platform = linux
12+
pretty = True
13+
14+
# Enable most stricter settings
15+
enable_error_code = ignore-without-code
16+
strict = True
17+
18+
# Various stricter settings that we can't yet enable
19+
# Try to enable these in the following order:
20+
strict_optional = False
21+
disallow_any_generics = False
22+
disallow_incomplete_defs = False
23+
disallow_untyped_calls = False
24+
disallow_untyped_defs = False
25+
check_untyped_defs = False
26+
warn_return_any = False
27+
28+
disable_error_code = return
29+
30+
# Various internal modules that typeshed deliberately doesn't have stubs for:
31+
[mypy-_abc.*]
32+
ignore_missing_imports = True
33+
34+
[mypy-_opcode.*]
35+
ignore_missing_imports = True
36+
37+
[mypy-_overlapped.*]
38+
ignore_missing_imports = True
39+
40+
[mypy-_testcapi.*]
41+
ignore_missing_imports = True
42+
43+
[mypy-_testinternalcapi.*]
44+
ignore_missing_imports = True
45+
46+
[mypy-test.*]
47+
ignore_missing_imports = True

Lib/test/libregrtest/refleak.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import sys
22
import warnings
33
from inspect import isabstract
4+
from typing import Any
45

56
from test import support
67
from test.support import os_helper
@@ -45,6 +46,7 @@ def runtest_refleak(test_name, test_func,
4546
fs = warnings.filters[:]
4647
ps = copyreg.dispatch_table.copy()
4748
pic = sys.path_importer_cache.copy()
49+
zdc: dict[str, Any] | None
4850
try:
4951
import zipimport
5052
except ImportError:

Lib/test/libregrtest/results.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def accumulate_result(self, result: TestResult, runtests: RunTests):
111111
def need_rerun(self):
112112
return bool(self.bad_results)
113113

114-
def prepare_rerun(self) -> (TestTuple, FilterDict):
114+
def prepare_rerun(self) -> tuple[TestTuple, FilterDict]:
115115
tests: TestList = []
116116
match_tests_dict = {}
117117
for result in self.bad_results:

Lib/test/libregrtest/run_workers.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from .runtests import RunTests, JsonFile, JsonFileType
2222
from .single import PROGRESS_MIN_TIME
2323
from .utils import (
24-
StrPath, StrJSON, TestName, MS_WINDOWS,
24+
StrPath, TestName, MS_WINDOWS,
2525
format_duration, print_warning, count, plural)
2626
from .worker import create_worker_process, USE_PROCESS_GROUP
2727

@@ -104,9 +104,9 @@ def __init__(self, worker_id: int, runner: "RunWorkers") -> None:
104104
self.output = runner.output
105105
self.timeout = runner.worker_timeout
106106
self.log = runner.log
107-
self.test_name = None
108-
self.start_time = None
109-
self._popen = None
107+
self.test_name: TestName | None = None
108+
self.start_time: float | None = None
109+
self._popen: subprocess.Popen[str] | None = None
110110
self._killed = False
111111
self._stopped = False
112112

@@ -160,7 +160,7 @@ def stop(self) -> None:
160160
self._kill()
161161

162162
def _run_process(self, runtests: RunTests, output_fd: int,
163-
tmp_dir: StrPath | None = None) -> int:
163+
tmp_dir: StrPath | None = None) -> int | None:
164164
popen = create_worker_process(runtests, output_fd, tmp_dir)
165165
self._popen = popen
166166
self._killed = False
@@ -260,7 +260,7 @@ def create_worker_runtests(self, test_name: TestName, json_file: JsonFile) -> Ru
260260
**kwargs)
261261

262262
def run_tmp_files(self, worker_runtests: RunTests,
263-
stdout_fd: int) -> (int, list[StrPath]):
263+
stdout_fd: int) -> tuple[int | None, list[StrPath]]:
264264
# gh-93353: Check for leaked temporary files in the parent process,
265265
# since the deletion of temporary files can happen late during
266266
# Python finalization: too late for libregrtest.
@@ -297,13 +297,13 @@ def read_json(self, json_file: JsonFile, json_tmpfile: TextIO | None,
297297
try:
298298
if json_tmpfile is not None:
299299
json_tmpfile.seek(0)
300-
worker_json: StrJSON = json_tmpfile.read()
300+
worker_json = json_tmpfile.read()
301301
elif json_file.file_type == JsonFileType.STDOUT:
302302
stdout, _, worker_json = stdout.rpartition("\n")
303303
stdout = stdout.rstrip()
304304
else:
305305
with json_file.open(encoding='utf8') as json_fp:
306-
worker_json: StrJSON = json_fp.read()
306+
worker_json = json_fp.read()
307307
except Exception as exc:
308308
# gh-101634: Catch UnicodeDecodeError if stdout cannot be
309309
# decoded from encoding
@@ -414,8 +414,8 @@ def wait_stopped(self, start_time: float) -> None:
414414
break
415415

416416

417-
def get_running(workers: list[WorkerThread]) -> list[str]:
418-
running = []
417+
def get_running(workers: list[WorkerThread]) -> str | None:
418+
running: list[str] = []
419419
for worker in workers:
420420
test_name = worker.test_name
421421
if not test_name:
@@ -431,7 +431,7 @@ def get_running(workers: list[WorkerThread]) -> list[str]:
431431

432432
class RunWorkers:
433433
def __init__(self, num_workers: int, runtests: RunTests,
434-
logger: Logger, results: TestResult) -> None:
434+
logger: Logger, results: TestResults) -> None:
435435
self.num_workers = num_workers
436436
self.runtests = runtests
437437
self.log = logger.log
@@ -446,10 +446,10 @@ def __init__(self, num_workers: int, runtests: RunTests,
446446
# Rely on faulthandler to kill a worker process. This timouet is
447447
# when faulthandler fails to kill a worker process. Give a maximum
448448
# of 5 minutes to faulthandler to kill the worker.
449-
self.worker_timeout = min(self.timeout * 1.5, self.timeout + 5 * 60)
449+
self.worker_timeout: float | None = min(self.timeout * 1.5, self.timeout + 5 * 60)
450450
else:
451451
self.worker_timeout = None
452-
self.workers = None
452+
self.workers: list[WorkerThread] | None = None
453453

454454
jobs = self.runtests.get_jobs()
455455
if jobs is not None:
@@ -529,7 +529,7 @@ def display_result(self, mp_result: MultiprocessResult) -> None:
529529
text += f' -- {running}'
530530
self.display_progress(self.test_index, text)
531531

532-
def _process_result(self, item: QueueOutput) -> bool:
532+
def _process_result(self, item: QueueOutput) -> TestResult:
533533
"""Returns True if test runner must stop."""
534534
if item[0]:
535535
# Thread got an exception

Lib/test/libregrtest/runtests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ class RunTests:
8888
use_junit: bool
8989
memory_limit: str | None
9090
gc_threshold: int | None
91-
use_resources: tuple[str]
92-
python_cmd: tuple[str] | None
91+
use_resources: tuple[str, ...]
92+
python_cmd: tuple[str, ...] | None
9393
randomize: bool
9494
random_seed: int | None
9595
json_file: JsonFile | None

Lib/test/libregrtest/setup.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import faulthandler
2+
import gc
23
import os
34
import random
45
import signal
56
import sys
67
import unittest
78
from test import support
89
from test.support.os_helper import TESTFN_UNDECODABLE, FS_NONASCII
9-
try:
10-
import gc
11-
except ImportError:
12-
gc = None
1310

1411
from .runtests import RunTests
1512
from .utils import (

Lib/test/libregrtest/single.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ def regrtest_runner(result: TestResult, test_func, runtests: RunTests) -> None:
5151
if refleak:
5252
result.state = State.REFLEAK
5353

54+
stats: TestStats | None
55+
5456
match test_result:
5557
case TestStats():
5658
stats = test_result

Lib/test/libregrtest/utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import sysconfig
1111
import tempfile
1212
import textwrap
13+
from collections.abc import Callable
1314

1415
from test import support
1516
from test.support import os_helper
@@ -67,7 +68,7 @@ def format_duration(seconds):
6768
return ' '.join(parts)
6869

6970

70-
def strip_py_suffix(names: list[str]):
71+
def strip_py_suffix(names: list[str] | None) -> None:
7172
if not names:
7273
return
7374
for idx, name in enumerate(names):
@@ -441,6 +442,7 @@ def remove_testfn(test_name: TestName, verbose: int) -> None:
441442
if not os.path.exists(name):
442443
return
443444

445+
nuker: Callable[[str], None]
444446
if os.path.isdir(name):
445447
import shutil
446448
kind, nuker = "directory", shutil.rmtree

Lib/test/libregrtest/worker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import subprocess
22
import sys
33
import os
4-
from typing import NoReturn
4+
from typing import Any, NoReturn
55

66
from test import support
77
from test.support import os_helper
@@ -45,7 +45,7 @@ def create_worker_process(runtests: RunTests, output_fd: int,
4545
# Running the child from the same working directory as regrtest's original
4646
# invocation ensures that TEMPDIR for the child is the same when
4747
# sysconfig.is_python_build() is true. See issue 15300.
48-
kwargs = dict(
48+
kwargs: dict[str, Any] = dict(
4949
env=env,
5050
stdout=output_fd,
5151
# bpo-45410: Write stderr into stdout to keep messages order

0 commit comments

Comments
 (0)