https://github.com/python/cpython/commit/ecfca207196aa77bd73e64368b44653fbc0f68dc
commit: ecfca207196aa77bd73e64368b44653fbc0f68dc
branch: 3.12
author: Hugo van Kemenade <1324225+hug...@users.noreply.github.com>
committer: hugovk <1324225+hug...@users.noreply.github.com>
date: 2025-02-20T15:47:10Z
summary:

[3.12] gh-119727: Add --single-process option to regrtest (GH-119728) (#130359)

Co-authored-by: Victor Stinner <vstin...@python.org>

files:
A Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst
M Lib/test/libregrtest/cmdline.py
M Lib/test/libregrtest/main.py
M Lib/test/test_regrtest.py

diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py
index 3211d04bee0c34..05b2e9fefc1f32 100644
--- a/Lib/test/libregrtest/cmdline.py
+++ b/Lib/test/libregrtest/cmdline.py
@@ -174,6 +174,7 @@ def __init__(self, **kwargs) -> None:
         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 '
@@ -436,6 +443,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:
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index 04404cbcd524e1..899ddf9d8d4b2f 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -87,12 +87,13 @@ def __init__(self, ns: Namespace, _add_python_opts: bool = 
False):
         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
 
@@ -234,7 +235,7 @@ def list_tests(tests: TestTuple):
 
     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
@@ -244,7 +245,6 @@ def _rerun_failed_tests(self, runtests: RunTests):
         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,
@@ -254,7 +254,15 @@ def _rerun_failed_tests(self, runtests: RunTests):
             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):
@@ -367,7 +375,7 @@ def run_tests_sequentially(self, runtests):
             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)
@@ -589,7 +597,7 @@ def _add_cross_compile_opts(self, regrtest_opts):
             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'])
diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py
index 75196ac040a87e..6c97f5e0d2188e 100644
--- a/Lib/test/test_regrtest.py
+++ b/Lib/test/test_regrtest.py
@@ -466,6 +466,19 @@ def test_verbose3_huntrleaks(self):
         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
index 00000000000000..bf28d8bb77b8a2
--- /dev/null
+++ b/Misc/NEWS.d/next/Tests/2024-05-29-15-28-08.gh-issue-119727.dVkaZM.rst
@@ -0,0 +1,2 @@
+Add ``--single-process`` command line option to Python test runner (regrtest).
+Patch by Victor Stinner.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to