Skip to content

Commit 7ddff04

Browse files
committed
gh-109566: regrtest reexecutes the process
regrtest now replaces the process with a new process to add options to the Python command line. Add options: "-u -W default -bb". When --fast-ci or --slow-ci option is used, the "-E" option is also added. The following methods to run the Python test suite don't replace the process: * "import test.autotest" * "from test.regrtest import main; main()" Changes: * PCbuild/rt.bat and Tools/scripts/run_tests.py no longer need to add "-u -W default -bb -E" options to Python: it's now done by regrtest. * Fix Tools/scripts/run_tests.py: flush stdout before replacing the process. Previously, buffered messages were lost.
1 parent 859618c commit 7ddff04

File tree

8 files changed

+53
-15
lines changed

8 files changed

+53
-15
lines changed

Lib/test/autotest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
# It can be especially handy if you're in an interactive shell, e.g.,
33
# from test import autotest.
44
from test.libregrtest.main import main
5-
main()
5+
main(reexec=False)

Lib/test/libregrtest/cmdline.py

+3
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ def __init__(self, **kwargs) -> None:
184184
self.threshold = None
185185
self.fail_rerun = False
186186
self.tempdir = None
187+
self.no_reexec = False
187188

188189
super().__init__(**kwargs)
189190

@@ -343,6 +344,8 @@ def _create_parser():
343344
help='override the working directory for the test run')
344345
group.add_argument('--cleanup', action='store_true',
345346
help='remove old test_python_* directories')
347+
group.add_argument('--no-reexec', action='store_true',
348+
help="internal option, don't use it")
346349
return parser
347350

348351

Lib/test/libregrtest/main.py

+38-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import random
33
import re
4+
import shlex
45
import sys
56
import time
67

@@ -20,7 +21,7 @@
2021
StrPath, StrJSON, TestName, TestList, TestTuple, FilterTuple,
2122
strip_py_suffix, count, format_duration,
2223
printlist, get_temp_dir, get_work_dir, exit_timeout,
23-
display_header, cleanup_temp_dir,
24+
display_header, cleanup_temp_dir, print_warning,
2425
MS_WINDOWS)
2526

2627

@@ -47,7 +48,7 @@ class Regrtest:
4748
directly to set the values that would normally be set by flags
4849
on the command line.
4950
"""
50-
def __init__(self, ns: Namespace):
51+
def __init__(self, ns: Namespace, reexec: bool = True):
5152
# Log verbosity
5253
self.verbose: int = int(ns.verbose)
5354
self.quiet: bool = ns.quiet
@@ -69,6 +70,7 @@ def __init__(self, ns: Namespace):
6970
self.want_cleanup: bool = ns.cleanup
7071
self.want_rerun: bool = ns.rerun
7172
self.want_run_leaks: bool = ns.runleaks
73+
self.want_reexec: bool = (reexec and not ns.no_reexec)
7274

7375
# Select tests
7476
if ns.match_tests:
@@ -95,6 +97,7 @@ def __init__(self, ns: Namespace):
9597
self.worker_json: StrJSON | None = ns.worker_json
9698

9799
# Options to run tests
100+
self.ci_mode: bool = (ns.fast_ci or ns.slow_ci)
98101
self.fail_fast: bool = ns.failfast
99102
self.fail_env_changed: bool = ns.fail_env_changed
100103
self.fail_rerun: bool = ns.fail_rerun
@@ -483,7 +486,38 @@ def run_tests(self, selected: TestTuple, tests: TestList | None) -> int:
483486
# processes.
484487
return self._run_tests(selected, tests)
485488

489+
def _reexecute_python(self):
490+
if self.python_cmd:
491+
# Do nothing if --python=cmd option is used
492+
return
493+
494+
python_opts = [
495+
'-u', # Unbuffered stdout and stderr
496+
'-W', 'default', # Add warnings filter 'default'
497+
'-bb', # Error on bytes/str comparison
498+
]
499+
if self.ci_mode:
500+
python_opts.append('-E') # Ignore PYTHON* environment variables
501+
502+
cmd = [*sys.orig_argv, "--no-reexec"]
503+
cmd[1:1] = python_opts
504+
505+
# Make sure that messages before execv() are logged
506+
sys.stdout.flush()
507+
sys.stderr.flush()
508+
509+
try:
510+
os.execv(cmd[0], cmd)
511+
# execv() do no return and so we don't get to this line on success
512+
except OSError as exc:
513+
cmd_text = shlex.join(cmd)
514+
print_warning(f"Failed to reexecute Python: {exc!r}\n"
515+
f"Command: {cmd_text}")
516+
486517
def main(self, tests: TestList | None = None):
518+
if self.want_reexec:
519+
self._reexecute_python()
520+
487521
if self.junit_filename and not os.path.isabs(self.junit_filename):
488522
self.junit_filename = os.path.abspath(self.junit_filename)
489523

@@ -515,7 +549,7 @@ def main(self, tests: TestList | None = None):
515549
sys.exit(exitcode)
516550

517551

518-
def main(tests=None, **kwargs):
552+
def main(tests=None, reexec=True, **kwargs):
519553
"""Run the Python suite."""
520554
ns = _parse_args(sys.argv[1:], **kwargs)
521-
Regrtest(ns).main(tests=tests)
555+
Regrtest(ns, reexec=reexec).main(tests=tests)

Lib/test/regrtest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def _main():
4040
# sanity check
4141
assert __file__ == os.path.abspath(sys.argv[0])
4242

43-
main()
43+
main(reexec=False)
4444

4545

4646
if __name__ == '__main__':

Lib/test/test_regrtest.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ def check_ci_mode(self, args, use_resources):
382382
# Check Regrtest attributes which are more reliable than Namespace
383383
# which has an unclear API
384384
regrtest = main.Regrtest(ns)
385-
self.assertNotEqual(regrtest.num_workers, 0)
385+
self.assertTrue(regrtest.ci_mode)
386+
self.assertGreaterEqual(regrtest.num_workers, 1)
386387
self.assertTrue(regrtest.want_rerun)
387388
self.assertTrue(regrtest.randomize)
388389
self.assertIsNone(regrtest.random_seed)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
regrtest now replaces the process with a new process to add options to the
2+
Python command line. Add options: ``-u -W default -bb``. When ``--fast-ci``
3+
or ``--slow-ci`` option is used, the ``-E`` option is also added. Patch by
4+
Victor Stinner.

PCbuild/rt.bat

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ if NOT "%1"=="" (set regrtestargs=%regrtestargs% %1) & shift & goto CheckOpts
4848

4949
if not defined prefix set prefix=%pcbuild%amd64
5050
set exe=%prefix%\python%suffix%.exe
51-
set cmd="%exe%" %dashO% -u -Wd -E -bb -m test %regrtestargs%
51+
set cmd="%exe%" %dashO% -m test %regrtestargs%
5252
if defined qmode goto Qmode
5353

5454
echo Deleting .pyc files ...

Tools/scripts/run_tests.py

+3-7
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,7 @@ def is_python_flag(arg):
2323

2424

2525
def main(regrtest_args):
26-
args = [sys.executable,
27-
'-u', # Unbuffered stdout and stderr
28-
'-W', 'default', # Warnings set to 'default'
29-
'-bb', # Warnings about bytes/bytearray
30-
]
26+
args = [sys.executable]
3127

3228
cross_compile = '_PYTHON_HOST_PLATFORM' in os.environ
3329
if (hostrunner := os.environ.get("_PYTHON_HOSTRUNNER")) is None:
@@ -47,7 +43,6 @@ def main(regrtest_args):
4743
}
4844
else:
4945
environ = os.environ.copy()
50-
args.append("-E")
5146

5247
# Allow user-specified interpreter options to override our defaults.
5348
args.extend(test.support.args_from_interpreter_flags())
@@ -70,7 +65,8 @@ def main(regrtest_args):
7065

7166
args.extend(regrtest_args)
7267

73-
print(shlex.join(args))
68+
print(shlex.join(args), flush=True)
69+
7470
if sys.platform == 'win32':
7571
from subprocess import call
7672
sys.exit(call(args))

0 commit comments

Comments
 (0)