Skip to content

Commit 26748ed

Browse files
authored
gh-110756: Sync regrtest with main branch (#110758) (#110781)
Copy files from main to this branch: * Lib/test/libregrtest/*.py * Lib/test/__init__.py * Lib/test/__main__.py * Lib/test/autotest.py * Lib/test/pythoninfo.py * Lib/test/regrtest.py * Lib/test/test_regrtest.py Copy also changes from: * Lib/test/support/__init__.py * Lib/test/support/os_helper.py * Lib/test/support/testresult.py * Lib/test/support/threading_helper.py * Lib/test/test_support.py Do not modify scripts running tests such as Makefile.pre.in, .github/workflows/build.yml or Tools/scripts/run_tests.py: do not use --fast-ci and --slow-ci in this change. Changes: * SPLITTESTDIRS: don't include test_inspect. * Add utils.process_cpu_count() using len(os.sched_getaffinity(0)). * test_regrtest doesn't use @support.without_optimizer which doesn't exist in Python 3.11. * Add support.set_sanitizer_env_var(). * Update test_faulthandler to use support.set_sanitizer_env_var(). * @support.without_optimizer doesn't exist in 3.11. * Add support.Py_DEBUG. * regrtest.refleak: 3.11 doesn't have sys.getunicodeinternedsize.
1 parent e16922f commit 26748ed

29 files changed

+3712
-2176
lines changed

Lib/test/__main__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from test.libregrtest import main
2-
main()
1+
from test.libregrtest.main import main
2+
main(_add_python_opts=True)

Lib/test/autotest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This should be equivalent to running regrtest.py from the cmdline.
22
# It can be especially handy if you're in an interactive shell, e.g.,
33
# from test import autotest.
4-
from test.libregrtest import main
4+
from test.libregrtest.main import main
55
main()

Lib/test/libregrtest/__init__.py

-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
from test.libregrtest.cmdline import _parse_args, RESOURCE_NAMES, ALL_RESOURCES
2-
from test.libregrtest.main import main

Lib/test/libregrtest/cmdline.py

+94-31
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import argparse
2-
import os
2+
import os.path
33
import shlex
44
import sys
55
from test.support import os_helper
6+
from .utils import ALL_RESOURCES, RESOURCE_NAMES
67

78

89
USAGE = """\
@@ -27,8 +28,10 @@
2728
Additional option details:
2829
2930
-r randomizes test execution order. You can use --randseed=int to provide an
30-
int seed value for the randomizer; this is useful for reproducing troublesome
31-
test orders.
31+
int seed value for the randomizer. The randseed value will be used
32+
to set seeds for all random usages in tests
33+
(including randomizing the tests order if -r is set).
34+
By default we always set random seed, but do not randomize test order.
3235
3336
-s On the first invocation of regrtest using -s, the first test file found
3437
or the first test file given on the command line is run, and the name of
@@ -130,25 +133,17 @@
130133
"""
131134

132135

133-
ALL_RESOURCES = ('audio', 'curses', 'largefile', 'network',
134-
'decimal', 'cpu', 'subprocess', 'urlfetch', 'gui', 'walltime')
135-
136-
# Other resources excluded from --use=all:
137-
#
138-
# - extralagefile (ex: test_zipfile64): really too slow to be enabled
139-
# "by default"
140-
# - tzdata: while needed to validate fully test_datetime, it makes
141-
# test_datetime too slow (15-20 min on some buildbots) and so is disabled by
142-
# default (see bpo-30822).
143-
RESOURCE_NAMES = ALL_RESOURCES + ('extralargefile', 'tzdata')
144-
145-
146136
class Namespace(argparse.Namespace):
147137
def __init__(self, **kwargs) -> None:
138+
self.ci = False
148139
self.testdir = None
149140
self.verbose = 0
150141
self.quiet = False
151142
self.exclude = False
143+
self.cleanup = False
144+
self.wait = False
145+
self.list_cases = False
146+
self.list_tests = False
152147
self.single = False
153148
self.randomize = False
154149
self.fromfile = None
@@ -157,8 +152,8 @@ def __init__(self, **kwargs) -> None:
157152
self.trace = False
158153
self.coverdir = 'coverage'
159154
self.runleaks = False
160-
self.huntrleaks = False
161-
self.verbose2 = False
155+
self.huntrleaks: tuple[int, int, str] | None = None
156+
self.rerun = False
162157
self.verbose3 = False
163158
self.print_slow = False
164159
self.random_seed = None
@@ -170,6 +165,14 @@ def __init__(self, **kwargs) -> None:
170165
self.ignore_tests = None
171166
self.pgo = False
172167
self.pgo_extended = False
168+
self.worker_json = None
169+
self.start = None
170+
self.timeout = None
171+
self.memlimit = None
172+
self.threshold = None
173+
self.fail_rerun = False
174+
self.tempdir = None
175+
self._add_python_opts = True
173176

174177
super().__init__(**kwargs)
175178

@@ -198,25 +201,35 @@ def _create_parser():
198201
# We add help explicitly to control what argument group it renders under.
199202
group.add_argument('-h', '--help', action='help',
200203
help='show this help message and exit')
201-
group.add_argument('--timeout', metavar='TIMEOUT', type=float,
204+
group.add_argument('--fast-ci', action='store_true',
205+
help='Fast Continuous Integration (CI) mode used by '
206+
'GitHub Actions')
207+
group.add_argument('--slow-ci', action='store_true',
208+
help='Slow Continuous Integration (CI) mode used by '
209+
'buildbot workers')
210+
group.add_argument('--timeout', metavar='TIMEOUT',
202211
help='dump the traceback and exit if a test takes '
203212
'more than TIMEOUT seconds; disabled if TIMEOUT '
204213
'is negative or equals to zero')
205214
group.add_argument('--wait', action='store_true',
206215
help='wait for user input, e.g., allow a debugger '
207216
'to be attached')
208-
group.add_argument('--worker-args', metavar='ARGS')
209217
group.add_argument('-S', '--start', metavar='START',
210218
help='the name of the test at which to start.' +
211219
more_details)
212220
group.add_argument('-p', '--python', metavar='PYTHON',
213221
help='Command to run Python test subprocesses with.')
222+
group.add_argument('--randseed', metavar='SEED',
223+
dest='random_seed', type=int,
224+
help='pass a global random seed')
214225

215226
group = parser.add_argument_group('Verbosity')
216227
group.add_argument('-v', '--verbose', action='count',
217228
help='run tests in verbose mode with output to stdout')
218-
group.add_argument('-w', '--verbose2', action='store_true',
229+
group.add_argument('-w', '--rerun', action='store_true',
219230
help='re-run failed tests in verbose mode')
231+
group.add_argument('--verbose2', action='store_true', dest='rerun',
232+
help='deprecated alias to --rerun')
220233
group.add_argument('-W', '--verbose3', action='store_true',
221234
help='display test output on failure')
222235
group.add_argument('-q', '--quiet', action='store_true',
@@ -229,10 +242,6 @@ def _create_parser():
229242
group = parser.add_argument_group('Selecting tests')
230243
group.add_argument('-r', '--randomize', action='store_true',
231244
help='randomize test execution order.' + more_details)
232-
group.add_argument('--randseed', metavar='SEED',
233-
dest='random_seed', type=int,
234-
help='pass a random seed to reproduce a previous '
235-
'random run')
236245
group.add_argument('-f', '--fromfile', metavar='FILE',
237246
help='read names of tests to run from a file.' +
238247
more_details)
@@ -311,6 +320,9 @@ def _create_parser():
311320
group.add_argument('--fail-env-changed', action='store_true',
312321
help='if a test file alters the environment, mark '
313322
'the test as failed')
323+
group.add_argument('--fail-rerun', action='store_true',
324+
help='if a test failed and then passed when re-run, '
325+
'mark the tests as failed')
314326

315327
group.add_argument('--junit-xml', dest='xmlpath', metavar='FILENAME',
316328
help='writes JUnit-style XML results to the specified '
@@ -319,6 +331,9 @@ def _create_parser():
319331
help='override the working directory for the test run')
320332
group.add_argument('--cleanup', action='store_true',
321333
help='remove old test_python_* directories')
334+
group.add_argument('--dont-add-python-opts', dest='_add_python_opts',
335+
action='store_false',
336+
help="internal option, don't use it")
322337
return parser
323338

324339

@@ -369,7 +384,50 @@ def _parse_args(args, **kwargs):
369384
for arg in ns.args:
370385
if arg.startswith('-'):
371386
parser.error("unrecognized arguments: %s" % arg)
372-
sys.exit(1)
387+
388+
if ns.timeout is not None:
389+
# Support "--timeout=" (no value) so Makefile.pre.pre TESTTIMEOUT
390+
# can be used by "make buildbottest" and "make test".
391+
if ns.timeout != "":
392+
try:
393+
ns.timeout = float(ns.timeout)
394+
except ValueError:
395+
parser.error(f"invalid timeout value: {ns.timeout!r}")
396+
else:
397+
ns.timeout = None
398+
399+
# Continuous Integration (CI): common options for fast/slow CI modes
400+
if ns.slow_ci or ns.fast_ci:
401+
# Similar to options:
402+
#
403+
# -j0 --randomize --fail-env-changed --fail-rerun --rerun
404+
# --slowest --verbose3
405+
if ns.use_mp is None:
406+
ns.use_mp = 0
407+
ns.randomize = True
408+
ns.fail_env_changed = True
409+
ns.fail_rerun = True
410+
if ns.python is None:
411+
ns.rerun = True
412+
ns.print_slow = True
413+
ns.verbose3 = True
414+
else:
415+
ns._add_python_opts = False
416+
417+
# When both --slow-ci and --fast-ci options are present,
418+
# --slow-ci has the priority
419+
if ns.slow_ci:
420+
# Similar to: -u "all" --timeout=1200
421+
if not ns.use:
422+
ns.use = [['all']]
423+
if ns.timeout is None:
424+
ns.timeout = 1200 # 20 minutes
425+
elif ns.fast_ci:
426+
# Similar to: -u "all,-cpu" --timeout=600
427+
if not ns.use:
428+
ns.use = [['all', '-cpu']]
429+
if ns.timeout is None:
430+
ns.timeout = 600 # 10 minutes
373431

374432
if ns.single and ns.fromfile:
375433
parser.error("-s and -f don't go together!")
@@ -382,7 +440,7 @@ def _parse_args(args, **kwargs):
382440
ns.python = shlex.split(ns.python)
383441
if ns.failfast and not (ns.verbose or ns.verbose3):
384442
parser.error("-G/--failfast needs either -v or -W")
385-
if ns.pgo and (ns.verbose or ns.verbose2 or ns.verbose3):
443+
if ns.pgo and (ns.verbose or ns.rerun or ns.verbose3):
386444
parser.error("--pgo/-v don't go together!")
387445
if ns.pgo_extended:
388446
ns.pgo = True # pgo_extended implies pgo
@@ -396,10 +454,6 @@ def _parse_args(args, **kwargs):
396454
if ns.timeout is not None:
397455
if ns.timeout <= 0:
398456
ns.timeout = None
399-
if ns.use_mp is not None:
400-
if ns.use_mp <= 0:
401-
# Use all cores + extras for tests that like to sleep
402-
ns.use_mp = 2 + (os.cpu_count() or 1)
403457
if ns.use:
404458
for a in ns.use:
405459
for r in a:
@@ -443,4 +497,13 @@ def _parse_args(args, **kwargs):
443497
# --forever implies --failfast
444498
ns.failfast = True
445499

500+
if ns.huntrleaks:
501+
warmup, repetitions, _ = ns.huntrleaks
502+
if warmup < 1 or repetitions < 1:
503+
msg = ("Invalid values for the --huntrleaks/-R parameters. The "
504+
"number of warmups and repetitions must be at least 1 "
505+
"each (1:1).")
506+
print(msg, file=sys.stderr, flush=True)
507+
sys.exit(2)
508+
446509
return ns

Lib/test/libregrtest/findtests.py

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import os
2+
import sys
3+
import unittest
4+
5+
from test import support
6+
7+
from .utils import (
8+
StrPath, TestName, TestTuple, TestList, FilterTuple,
9+
abs_module_name, count, printlist)
10+
11+
12+
# If these test directories are encountered recurse into them and treat each
13+
# "test_*.py" file or each sub-directory as a separate test module. This can
14+
# increase parallelism.
15+
#
16+
# Beware this can't generally be done for any directory with sub-tests as the
17+
# __init__.py may do things which alter what tests are to be run.
18+
SPLITTESTDIRS: set[TestName] = {
19+
"test_asyncio",
20+
"test_concurrent_futures",
21+
"test_future_stmt",
22+
"test_gdb",
23+
"test_multiprocessing_fork",
24+
"test_multiprocessing_forkserver",
25+
"test_multiprocessing_spawn",
26+
}
27+
28+
29+
def findtestdir(path: StrPath | None = None) -> StrPath:
30+
return path or os.path.dirname(os.path.dirname(__file__)) or os.curdir
31+
32+
33+
def findtests(*, testdir: StrPath | None = None, exclude=(),
34+
split_test_dirs: set[TestName] = SPLITTESTDIRS,
35+
base_mod: str = "") -> TestList:
36+
"""Return a list of all applicable test modules."""
37+
testdir = findtestdir(testdir)
38+
tests = []
39+
for name in os.listdir(testdir):
40+
mod, ext = os.path.splitext(name)
41+
if (not mod.startswith("test_")) or (mod in exclude):
42+
continue
43+
if base_mod:
44+
fullname = f"{base_mod}.{mod}"
45+
else:
46+
fullname = mod
47+
if fullname in split_test_dirs:
48+
subdir = os.path.join(testdir, mod)
49+
if not base_mod:
50+
fullname = f"test.{mod}"
51+
tests.extend(findtests(testdir=subdir, exclude=exclude,
52+
split_test_dirs=split_test_dirs,
53+
base_mod=fullname))
54+
elif ext in (".py", ""):
55+
tests.append(fullname)
56+
return sorted(tests)
57+
58+
59+
def split_test_packages(tests, *, testdir: StrPath | None = None, exclude=(),
60+
split_test_dirs=SPLITTESTDIRS):
61+
testdir = findtestdir(testdir)
62+
splitted = []
63+
for name in tests:
64+
if name in split_test_dirs:
65+
subdir = os.path.join(testdir, name)
66+
splitted.extend(findtests(testdir=subdir, exclude=exclude,
67+
split_test_dirs=split_test_dirs,
68+
base_mod=name))
69+
else:
70+
splitted.append(name)
71+
return splitted
72+
73+
74+
def _list_cases(suite):
75+
for test in suite:
76+
if isinstance(test, unittest.loader._FailedTest):
77+
continue
78+
if isinstance(test, unittest.TestSuite):
79+
_list_cases(test)
80+
elif isinstance(test, unittest.TestCase):
81+
if support.match_test(test):
82+
print(test.id())
83+
84+
def list_cases(tests: TestTuple, *,
85+
match_tests: FilterTuple | None = None,
86+
ignore_tests: FilterTuple | None = None,
87+
test_dir: StrPath | None = None):
88+
support.verbose = False
89+
support.set_match_tests(match_tests, ignore_tests)
90+
91+
skipped = []
92+
for test_name in tests:
93+
module_name = abs_module_name(test_name, test_dir)
94+
try:
95+
suite = unittest.defaultTestLoader.loadTestsFromName(module_name)
96+
_list_cases(suite)
97+
except unittest.SkipTest:
98+
skipped.append(test_name)
99+
100+
if skipped:
101+
sys.stdout.flush()
102+
stderr = sys.stderr
103+
print(file=stderr)
104+
print(count(len(skipped), "test"), "skipped:", file=stderr)
105+
printlist(skipped, file=stderr)

0 commit comments

Comments
 (0)