]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-119727: Add --single-process option to regrtest (#119728)
authorVictor Stinner <vstinner@python.org>
Mon, 3 Jun 2024 16:34:36 +0000 (18:34 +0200)
committerGitHub <noreply@github.com>
Mon, 3 Jun 2024 16:34:36 +0000 (16:34 +0000)
Lib/test/libregrtest/cmdline.py
Lib/test/libregrtest/main.py
Lib/test/libregrtest/worker.py
Lib/test/test_regrtest.py
Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst [new file with mode: 0644]

index d4dac77b250ad6877a8a03eb14b5541a96d1c314..2ff4715e82a41bc952f1b0cbc690de99c0eb1489 100644 (file)
@@ -174,6 +174,7 @@ class Namespace(argparse.Namespace):
         self.tempdir = None
         self._add_python_opts = True
         self.xmlpath = None
+        self.single_process = False
 
         super().__init__(**kwargs)
 
@@ -307,6 +308,12 @@ def _create_parser():
     group.add_argument('-j', '--multiprocess', metavar='PROCESSES',
                        dest='use_mp', type=int,
                        help='run PROCESSES processes at once')
+    group.add_argument('--single-process', action='store_true',
+                       dest='single_process',
+                       help='always run all tests sequentially in '
+                            'a single process, ignore -jN option, '
+                            'and failed tests are also rerun sequentially '
+                            'in the same process')
     group.add_argument('-T', '--coverage', action='store_true',
                        dest='trace',
                        help='turn on code coverage tracing using the trace '
@@ -435,6 +442,10 @@ def _parse_args(args, **kwargs):
     else:
         ns._add_python_opts = False
 
+    # --singleprocess overrides -jN option
+    if ns.single_process:
+        ns.use_mp = None
+
     # When both --slow-ci and --fast-ci options are present,
     # --slow-ci has the priority
     if ns.slow_ci:
index 9e7a7d608800914537a8470f1438521c57344e93..5148d3070513e8b73d675070d075bbba9d3640c7 100644 (file)
@@ -89,12 +89,13 @@ class Regrtest:
         self.cmdline_args: TestList = ns.args
 
         # Workers
-        if ns.use_mp is None:
-            num_workers = 0  # run sequentially
+        self.single_process: bool = ns.single_process
+        if self.single_process or ns.use_mp is None:
+            num_workers = 0   # run sequentially in a single process
         elif ns.use_mp <= 0:
-            num_workers = -1  # use the number of CPUs
+            num_workers = -1  # run in parallel, use the number of CPUs
         else:
-            num_workers = ns.use_mp
+            num_workers = ns.use_mp  # run in parallel
         self.num_workers: int = num_workers
         self.worker_json: StrJSON | None = ns.worker_json
 
@@ -236,7 +237,7 @@ class Regrtest:
 
     def _rerun_failed_tests(self, runtests: RunTests):
         # Configure the runner to re-run tests
-        if self.num_workers == 0:
+        if self.num_workers == 0 and not self.single_process:
             # Always run tests in fresh processes to have more deterministic
             # initial state. Don't re-run tests in parallel but limit to a
             # single worker process to have side effects (on the system load
@@ -246,7 +247,6 @@ class Regrtest:
         tests, match_tests_dict = self.results.prepare_rerun()
 
         # Re-run failed tests
-        self.log(f"Re-running {len(tests)} failed tests in verbose mode in subprocesses")
         runtests = runtests.copy(
             tests=tests,
             rerun=True,
@@ -256,7 +256,15 @@ class Regrtest:
             match_tests_dict=match_tests_dict,
             output_on_failure=False)
         self.logger.set_tests(runtests)
-        self._run_tests_mp(runtests, self.num_workers)
+
+        msg = f"Re-running {len(tests)} failed tests in verbose mode"
+        if not self.single_process:
+            msg = f"{msg} in subprocesses"
+            self.log(msg)
+            self._run_tests_mp(runtests, self.num_workers)
+        else:
+            self.log(msg)
+            self.run_tests_sequentially(runtests)
         return runtests
 
     def rerun_failed_tests(self, runtests: RunTests):
@@ -371,7 +379,7 @@ class Regrtest:
             tests = count(jobs, 'test')
         else:
             tests = 'tests'
-        msg = f"Run {tests} sequentially"
+        msg = f"Run {tests} sequentially in a single process"
         if runtests.timeout:
             msg += " (timeout: %s)" % format_duration(runtests.timeout)
         self.log(msg)
@@ -599,7 +607,7 @@ class Regrtest:
             keep_environ = True
 
         if cross_compile and hostrunner:
-            if self.num_workers == 0:
+            if self.num_workers == 0 and not self.single_process:
                 # For now use only two cores for cross-compiled builds;
                 # hostrunner can be expensive.
                 regrtest_opts.extend(['-j', '2'])
index 15d32b5baa04d09c8a7cb6ad46dda252ae334bcc..86cc30835fdbda64040a682fe3e54c5a8eddd2b5 100644 (file)
@@ -14,9 +14,9 @@ from .utils import (
 
 
 USE_PROCESS_GROUP = (hasattr(os, "setsid") and hasattr(os, "killpg"))
-NEED_TTY = set('''
-    test_ioctl
-'''.split())
+NEED_TTY = {
+    'test_ioctl',
+}
 
 
 def create_worker_process(runtests: WorkerRunTests, output_fd: int,
index 17eff617a56aa42d6781c84c7fcaf6172c689f2a..97ce797f0f6acb562c389bba747d20b9f6232643 100644 (file)
@@ -473,6 +473,19 @@ class ParseArgsTestCase(unittest.TestCase):
         self.assertEqual(regrtest.hunt_refleak.runs, 10)
         self.assertFalse(regrtest.output_on_failure)
 
+    def test_single_process(self):
+        args = ['-j2', '--single-process']
+        with support.captured_stderr():
+            regrtest = self.create_regrtest(args)
+        self.assertEqual(regrtest.num_workers, 0)
+        self.assertTrue(regrtest.single_process)
+
+        args = ['--fast-ci', '--single-process']
+        with support.captured_stderr():
+            regrtest = self.create_regrtest(args)
+        self.assertEqual(regrtest.num_workers, 0)
+        self.assertTrue(regrtest.single_process)
+
 
 @dataclasses.dataclass(slots=True)
 class Rerun:
diff --git a/Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst b/Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst
new file mode 100644 (file)
index 0000000..bf28d8b
--- /dev/null
@@ -0,0 +1,2 @@
+Add ``--single-process`` command line option to Python test runner (regrtest).
+Patch by Victor Stinner.