]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-109162: Refactor Regrtest.main() (#109163)
authorVictor Stinner <vstinner@python.org>
Fri, 8 Sep 2023 22:41:26 +0000 (00:41 +0200)
committerGitHub <noreply@github.com>
Fri, 8 Sep 2023 22:41:26 +0000 (22:41 +0000)
* 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.

Lib/test/libregrtest/cmdline.py
Lib/test/libregrtest/main.py
Lib/test/libregrtest/runtest.py
Lib/test/libregrtest/runtest_mp.py

index d1a590d8c1a5b31f1633bf123453e20de7ab6cdf..bbac980a0bf5d82018a8e868bc430187ee19240c 100644 (file)
@@ -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
index ab03647ca5802fd68c104e409f9b760150a51cb5..f973f03ab2651296d6a4d9ea2df9e0b9610d4963 100644 (file)
@@ -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)
index 16ae04191da7688ba093cefd69692901fb6f544c..7e4b2e6a36b452def70512d1c43e5ead4d61cd0c 100644 (file)
@@ -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
index 60089554cab5dd047571cb1b77b40cc2aeebcb13..2ecdfca0e770105882769dbeca787e62d17df78c 100644 (file)
@@ -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):