summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-09-08 22:41:26 (GMT)
committerGitHub <noreply@github.com>2023-09-08 22:41:26 (GMT)
commit5b7303e2653a0723a3e4c767d03dd02681206ca8 (patch)
treeb1ea2e62190674cb8d70f3f56a8f006c26aec649
parentbcb2ab5ef8c646565b09c860fb14e415d7b374bd (diff)
downloadcpython-5b7303e2653a0723a3e4c767d03dd02681206ca8.zip
cpython-5b7303e2653a0723a3e4c767d03dd02681206ca8.tar.gz
cpython-5b7303e2653a0723a3e4c767d03dd02681206ca8.tar.bz2
gh-109162: Refactor Regrtest.main() (#109163)
* main() now calls _parse_args() and pass 'ns' to Regrtest constructor. Remove kwargs argument from Regrtest.main(). * _parse_args() checks ns.huntrleaks. * set_temp_dir() is now responsible to call expanduser(). * Regrtest.main() sets self.tests earlier. * Add TestTuple and TestList types. * Rename MatchTests to FilterTuple and rename MatchTestsDict to FilterTestDict. * TestResult.get_rerun_match_tests() return type is now FilterTuple: return a tuple instead of a list. RunTests.tests type becomes TestTuple.
-rw-r--r--Lib/test/libregrtest/cmdline.py9
-rw-r--r--Lib/test/libregrtest/main.py87
-rw-r--r--Lib/test/libregrtest/runtest.py26
-rw-r--r--Lib/test/libregrtest/runtest_mp.py4
4 files changed, 64 insertions, 62 deletions
diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py
index d1a590d..bbac980 100644
--- a/Lib/test/libregrtest/cmdline.py
+++ b/Lib/test/libregrtest/cmdline.py
@@ -448,4 +448,13 @@ def _parse_args(args, **kwargs):
# --forever implies --failfast
ns.failfast = True
+ if ns.huntrleaks:
+ warmup, repetitions, _ = ns.huntrleaks
+ if warmup < 1 or repetitions < 1:
+ msg = ("Invalid values for the --huntrleaks/-R parameters. The "
+ "number of warmups and repetitions must be at least 1 "
+ "each (1:1).")
+ print(msg, file=sys.stderr, flush=True)
+ sys.exit(2)
+
return ns
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index ab03647..f973f03 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -9,10 +9,10 @@ import sysconfig
import tempfile
import time
import unittest
-from test.libregrtest.cmdline import _parse_args
+from test.libregrtest.cmdline import _parse_args, Namespace
from test.libregrtest.runtest import (
findtests, split_test_packages, runtest, abs_module_name,
- PROGRESS_MIN_TIME, State, MatchTestsDict, RunTests)
+ PROGRESS_MIN_TIME, State, FilterDict, RunTests, TestResult, TestList)
from test.libregrtest.setup import setup_tests
from test.libregrtest.pgo import setup_pgo_tests
from test.libregrtest.utils import (strip_py_suffix, count, format_duration,
@@ -58,9 +58,9 @@ class Regrtest:
directly to set the values that would normally be set by flags
on the command line.
"""
- def __init__(self):
+ def __init__(self, ns: Namespace):
# Namespace of command line options
- self.ns = None
+ self.ns: Namespace = ns
# tests
self.tests = []
@@ -68,14 +68,14 @@ class Regrtest:
self.all_runtests: list[RunTests] = []
# test results
- self.good: list[str] = []
- self.bad: list[str] = []
- self.rerun_bad: list[str] = []
- self.skipped: list[str] = []
- self.resource_denied: list[str] = []
- self.environment_changed: list[str] = []
- self.run_no_tests: list[str] = []
- self.rerun: list[str] = []
+ self.good: TestList = []
+ self.bad: TestList = []
+ self.rerun_bad: TestList = []
+ self.skipped: TestList = []
+ self.resource_denied: TestList = []
+ self.environment_changed: TestList = []
+ self.run_no_tests: TestList = []
+ self.rerun: TestList = []
self.need_rerun: list[TestResult] = []
self.first_state: str | None = None
@@ -184,29 +184,7 @@ class Regrtest:
line = f"{line}/{fails}"
self.log(f"[{line}] {text}")
- def parse_args(self, kwargs):
- ns = _parse_args(sys.argv[1:], **kwargs)
-
- if ns.xmlpath:
- support.junit_xml_list = self.testsuite_xml = []
-
- strip_py_suffix(ns.args)
-
- if ns.huntrleaks:
- warmup, repetitions, _ = ns.huntrleaks
- if warmup < 1 or repetitions < 1:
- msg = ("Invalid values for the --huntrleaks/-R parameters. The "
- "number of warmups and repetitions must be at least 1 "
- "each (1:1).")
- print(msg, file=sys.stderr, flush=True)
- sys.exit(2)
-
- if ns.tempdir:
- ns.tempdir = os.path.expanduser(ns.tempdir)
-
- self.ns = ns
-
- def find_tests(self, tests):
+ def find_tests(self):
ns = self.ns
single = ns.single
fromfile = ns.fromfile
@@ -216,8 +194,6 @@ class Regrtest:
starting_test = ns.start
randomize = ns.randomize
- self.tests = tests
-
if single:
self.next_single_filename = os.path.join(self.tmp_dir, 'pynexttest')
try:
@@ -321,7 +297,7 @@ class Regrtest:
print(count(len(skipped), "test"), "skipped:", file=stderr)
printlist(skipped, file=stderr)
- def get_rerun_match(self, rerun_list) -> MatchTestsDict:
+ def get_rerun_match(self, rerun_list) -> FilterDict:
rerun_match_tests = {}
for result in rerun_list:
match_tests = result.get_rerun_match_tests()
@@ -352,7 +328,7 @@ class Regrtest:
# Re-run failed tests
self.log(f"Re-running {len(tests)} failed tests in verbose mode in subprocesses")
- runtests = RunTests(tests, match_tests=match_tests, rerun=True)
+ runtests = RunTests(tuple(tests), match_tests=match_tests, rerun=True)
self.all_runtests.append(runtests)
self._run_tests_mp(runtests)
@@ -624,7 +600,7 @@ class Regrtest:
tests = self.selected
self.set_tests(tests)
- runtests = RunTests(tests, forever=self.ns.forever)
+ runtests = RunTests(tuple(tests), forever=self.ns.forever)
self.all_runtests.append(runtests)
if self.ns.use_mp:
self._run_tests_mp(runtests)
@@ -737,8 +713,12 @@ class Regrtest:
os.umask(old_mask)
def set_temp_dir(self):
- if self.ns.tempdir:
- self.tmp_dir = self.ns.tempdir
+ ns = self.ns
+ if ns.tempdir:
+ ns.tempdir = os.path.expanduser(ns.tempdir)
+
+ if ns.tempdir:
+ self.tmp_dir = ns.tempdir
if not self.tmp_dir:
# When tests are run from the Python build directory, it is best practice
@@ -795,14 +775,20 @@ class Regrtest:
print("Remove file: %s" % name)
os_helper.unlink(name)
- def main(self, tests=None, **kwargs):
- self.parse_args(kwargs)
+ def main(self, tests: TestList | None = None):
+ ns = self.ns
+ self.tests = tests
+
+ if ns.xmlpath:
+ support.junit_xml_list = self.testsuite_xml = []
+
+ strip_py_suffix(ns.args)
self.set_temp_dir()
self.fix_umask()
- if self.ns.cleanup:
+ if ns.cleanup:
self.cleanup()
sys.exit(0)
@@ -817,9 +803,9 @@ class Regrtest:
# When using multiprocessing, worker processes will use test_cwd
# as their parent temporary directory. So when the main process
# exit, it removes also subdirectories of worker processes.
- self.ns.tempdir = test_cwd
+ ns.tempdir = test_cwd
- self._main(tests, kwargs)
+ self._main()
except SystemExit as exc:
# bpo-38203: Python can hang at exit in Py_Finalize(), especially
# on threading._shutdown() call: put a timeout
@@ -862,7 +848,7 @@ class Regrtest:
self.display_summary()
self.finalize()
- def _main(self, tests, kwargs):
+ def _main(self):
if self.is_worker():
from test.libregrtest.runtest_mp import run_tests_worker
run_tests_worker(self.ns.worker_args)
@@ -872,7 +858,7 @@ class Regrtest:
input("Press any key to continue...")
setup_tests(self.ns)
- self.find_tests(tests)
+ self.find_tests()
exitcode = 0
if self.ns.list_tests:
@@ -888,4 +874,5 @@ class Regrtest:
def main(tests=None, **kwargs):
"""Run the Python suite."""
- Regrtest().main(tests=tests, **kwargs)
+ ns = _parse_args(sys.argv[1:], **kwargs)
+ Regrtest(ns).main(tests=tests)
diff --git a/Lib/test/libregrtest/runtest.py b/Lib/test/libregrtest/runtest.py
index 16ae041..7e4b2e6 100644
--- a/Lib/test/libregrtest/runtest.py
+++ b/Lib/test/libregrtest/runtest.py
@@ -19,8 +19,13 @@ from test.libregrtest.save_env import saved_test_environment
from test.libregrtest.utils import clear_caches, format_duration, print_warning
-MatchTests = list[str]
-MatchTestsDict = dict[str, MatchTests]
+TestTuple = list[str]
+TestList = list[str]
+
+# --match and --ignore options: list of patterns
+# ('*' joker character can be used)
+FilterTuple = tuple[str, ...]
+FilterDict = dict[str, FilterTuple]
# Avoid enum.Enum to reduce the number of imports when tests are run
@@ -174,7 +179,7 @@ class TestResult:
return True
return False
- def get_rerun_match_tests(self):
+ def get_rerun_match_tests(self) -> FilterTuple | None:
match_tests = []
errors = self.errors or []
@@ -195,29 +200,30 @@ class TestResult:
return None
match_tests.append(match_name)
- return match_tests
+ if not match_tests:
+ return None
+ return tuple(match_tests)
@dataclasses.dataclass(slots=True, frozen=True)
class RunTests:
- tests: list[str]
- match_tests: MatchTestsDict | None = None
+ tests: TestTuple
+ match_tests: FilterDict | None = None
rerun: bool = False
forever: bool = False
- def get_match_tests(self, test_name) -> MatchTests | None:
+ def get_match_tests(self, test_name) -> FilterTuple | None:
if self.match_tests is not None:
return self.match_tests.get(test_name, None)
else:
return None
def iter_tests(self):
- tests = tuple(self.tests)
if self.forever:
while True:
- yield from tests
+ yield from self.tests
else:
- yield from tests
+ yield from self.tests
# Minimum duration of a test to display its duration or to mention that
diff --git a/Lib/test/libregrtest/runtest_mp.py b/Lib/test/libregrtest/runtest_mp.py
index 6008955..2ecdfca 100644
--- a/Lib/test/libregrtest/runtest_mp.py
+++ b/Lib/test/libregrtest/runtest_mp.py
@@ -20,7 +20,7 @@ from test.libregrtest.cmdline import Namespace
from test.libregrtest.main import Regrtest
from test.libregrtest.runtest import (
runtest, TestResult, State, PROGRESS_MIN_TIME,
- MatchTests, RunTests)
+ FilterTuple, RunTests)
from test.libregrtest.setup import setup_tests
from test.libregrtest.utils import format_duration, print_warning
@@ -49,7 +49,7 @@ class WorkerJob:
test_name: str
namespace: Namespace
rerun: bool = False
- match_tests: MatchTests | None = None
+ match_tests: FilterTuple | None = None
class _EncodeWorkerJob(json.JSONEncoder):