Skip to content

Commit 8639d99

Browse files
committed
pythongh-109162: Regrtest copies 'ns' attributes
* Regrtest.__init__() now copies 'ns' namespace attributes to Regrtest attributes. Regrtest match_tests and ignore_tests attributes have type FilterTuple (tuple), instead of a list. * Add RunTests.copy(). Regrtest._rerun_failed_tests() now uses RunTests.copy(). * Replace Regrtest.all_tests (list) with Regrtest.first_runtests (RunTests). * Make random_seed maximum 10x larger (9 digits, instead of 8).
1 parent 5b7303e commit 8639d99

File tree

3 files changed

+73
-48
lines changed

3 files changed

+73
-48
lines changed

Lib/test/libregrtest/main.py

+67-47
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
from test.libregrtest.cmdline import _parse_args, Namespace
1313
from test.libregrtest.runtest import (
1414
findtests, split_test_packages, runtest, abs_module_name,
15-
PROGRESS_MIN_TIME, State, FilterDict, RunTests, TestResult, TestList)
15+
PROGRESS_MIN_TIME, State, RunTests, TestResult,
16+
FilterTuple, FilterDict, TestList)
1617
from test.libregrtest.setup import setup_tests
1718
from test.libregrtest.pgo import setup_pgo_tests
1819
from test.libregrtest.utils import (strip_py_suffix, count, format_duration,
@@ -62,10 +63,35 @@ def __init__(self, ns: Namespace):
6263
# Namespace of command line options
6364
self.ns: Namespace = ns
6465

66+
# Actions
67+
self.want_header = ns.header
68+
self.want_list_tests = ns.list_tests
69+
self.want_list_cases = ns.list_cases
70+
self.want_wait = ns.wait
71+
self.want_cleanup = ns.cleanup
72+
73+
# Select tests
74+
if ns.match_tests:
75+
self.match_tests: FilterTuple = tuple(ns.match_tests)
76+
else:
77+
self.match_tests = None
78+
if ns.ignore_tests:
79+
self.ignore_tests: FilterTuple = tuple(ns.ignore_tests)
80+
else:
81+
self.ignore_tests = None
82+
self.exclude = ns.exclude
83+
self.fromfile = ns.fromfile
84+
self.starting_test = ns.start
85+
86+
# Options to run tests
87+
self.forever = ns.forever
88+
self.randomize = ns.randomize
89+
self.random_seed = ns.random_seed
90+
6591
# tests
6692
self.tests = []
6793
self.selected = []
68-
self.all_runtests: list[RunTests] = []
94+
self.first_runtests: RunTests | None = None
6995

7096
# test results
7197
self.good: TestList = []
@@ -187,12 +213,8 @@ def display_progress(self, test_index, text):
187213
def find_tests(self):
188214
ns = self.ns
189215
single = ns.single
190-
fromfile = ns.fromfile
191216
pgo = ns.pgo
192-
exclude = ns.exclude
193217
test_dir = ns.testdir
194-
starting_test = ns.start
195-
randomize = ns.randomize
196218

197219
if single:
198220
self.next_single_filename = os.path.join(self.tmp_dir, 'pynexttest')
@@ -203,12 +225,12 @@ def find_tests(self):
203225
except OSError:
204226
pass
205227

206-
if fromfile:
228+
if self.fromfile:
207229
self.tests = []
208230
# regex to match 'test_builtin' in line:
209231
# '0:00:00 [ 4/400] test_builtin -- test_dict took 1 sec'
210232
regex = re.compile(r'\btest_[a-zA-Z0-9_]+\b')
211-
with open(os.path.join(os_helper.SAVEDCWD, fromfile)) as fp:
233+
with open(os.path.join(os_helper.SAVEDCWD, self.fromfile)) as fp:
212234
for line in fp:
213235
line = line.split('#', 1)[0]
214236
line = line.strip()
@@ -223,14 +245,14 @@ def find_tests(self):
223245
setup_pgo_tests(ns)
224246

225247
exclude_tests = set()
226-
if exclude:
248+
if self.exclude:
227249
for arg in ns.args:
228250
exclude_tests.add(arg)
229251
ns.args = []
230252

231253
alltests = findtests(testdir=test_dir, exclude=exclude_tests)
232254

233-
if not fromfile:
255+
if not self.fromfile:
234256
self.selected = self.tests or ns.args
235257
if self.selected:
236258
self.selected = split_test_packages(self.selected)
@@ -248,17 +270,17 @@ def find_tests(self):
248270
pass
249271

250272
# Remove all the selected tests that precede start if it's set.
251-
if starting_test:
273+
if self.starting_test:
252274
try:
253-
del self.selected[:self.selected.index(starting_test)]
275+
del self.selected[:self.selected.index(self.starting_test)]
254276
except ValueError:
255-
print(f"Cannot find starting test: {starting_test}")
277+
print(f"Cannot find starting test: {self.starting_test}")
256278
sys.exit(1)
257279

258-
if randomize:
259-
if ns.random_seed is None:
260-
ns.random_seed = random.randrange(10000000)
261-
random.seed(ns.random_seed)
280+
if self.randomize:
281+
if self.random_seed is None:
282+
self.random_seed = random.randrange(100_000_000)
283+
random.seed(self.random_seed)
262284
random.shuffle(self.selected)
263285

264286
def list_tests(self):
@@ -279,7 +301,7 @@ def list_cases(self):
279301
ns = self.ns
280302
test_dir = ns.testdir
281303
support.verbose = False
282-
support.set_match_tests(ns.match_tests, ns.ignore_tests)
304+
support.set_match_tests(self.match_tests, self.ignore_tests)
283305

284306
skipped = []
285307
for test_name in self.selected:
@@ -306,20 +328,18 @@ def get_rerun_match(self, rerun_list) -> FilterDict:
306328
rerun_match_tests[result.test_name] = match_tests
307329
return rerun_match_tests
308330

309-
def _rerun_failed_tests(self, need_rerun):
331+
def _rerun_failed_tests(self, need_rerun, runtests: RunTests):
310332
# Configure the runner to re-run tests
311333
ns = self.ns
312334
ns.verbose = True
313335
ns.failfast = False
314336
ns.verbose3 = False
315-
ns.forever = False
316337
if ns.use_mp is None:
317338
ns.use_mp = 1
318339

319340
# Get tests to re-run
320341
tests = [result.test_name for result in need_rerun]
321342
match_tests = self.get_rerun_match(need_rerun)
322-
self.set_tests(tests)
323343

324344
# Clear previously failed tests
325345
self.rerun_bad.extend(self.bad)
@@ -328,11 +348,14 @@ def _rerun_failed_tests(self, need_rerun):
328348

329349
# Re-run failed tests
330350
self.log(f"Re-running {len(tests)} failed tests in verbose mode in subprocesses")
331-
runtests = RunTests(tuple(tests), match_tests=match_tests, rerun=True)
332-
self.all_runtests.append(runtests)
351+
runtests = runtests.copy(tests=tuple(tests),
352+
match_tests=match_tests,
353+
rerun=True,
354+
forever=False)
355+
self.set_tests(runtests)
333356
self._run_tests_mp(runtests)
334357

335-
def rerun_failed_tests(self, need_rerun):
358+
def rerun_failed_tests(self, need_rerun, runtests: RunTests):
336359
if self.ns.python:
337360
# Temp patch for https://github.com/python/cpython/issues/94052
338361
self.log(
@@ -344,7 +367,7 @@ def rerun_failed_tests(self, need_rerun):
344367
self.first_state = self.get_tests_state()
345368

346369
print()
347-
self._rerun_failed_tests(need_rerun)
370+
self._rerun_failed_tests(need_rerun, runtests)
348371

349372
if self.bad:
350373
print(count(len(self.bad), 'test'), "failed again:")
@@ -572,9 +595,9 @@ def _run_tests_mp(self, runtests: RunTests) -> None:
572595
self.win_load_tracker.close()
573596
self.win_load_tracker = None
574597

575-
def set_tests(self, tests):
576-
self.tests = tests
577-
if self.ns.forever:
598+
def set_tests(self, runtests: RunTests):
599+
self.tests = runtests.tests
600+
if runtests.forever:
578601
self.test_count_text = ''
579602
self.test_count_width = 3
580603
else:
@@ -583,7 +606,7 @@ def set_tests(self, tests):
583606

584607
def run_tests(self):
585608
# For a partial run, we do not need to clutter the output.
586-
if (self.ns.header
609+
if (self.want_header
587610
or not(self.ns.pgo or self.ns.quiet or self.ns.single
588611
or self.tests or self.ns.args)):
589612
self.display_header()
@@ -595,17 +618,18 @@ def run_tests(self):
595618
"3 warmup repetitions can give false positives!")
596619
print(msg, file=sys.stdout, flush=True)
597620

598-
if self.ns.randomize:
599-
print("Using random seed", self.ns.random_seed)
621+
if self.randomize:
622+
print("Using random seed", self.random_seed)
600623

601624
tests = self.selected
602-
self.set_tests(tests)
603-
runtests = RunTests(tuple(tests), forever=self.ns.forever)
604-
self.all_runtests.append(runtests)
625+
runtests = RunTests(tuple(tests), forever=self.forever)
626+
self.first_runtests = runtests
627+
self.set_tests(runtests)
605628
if self.ns.use_mp:
606629
self._run_tests_mp(runtests)
607630
else:
608631
self.run_tests_sequentially(runtests)
632+
return runtests
609633

610634
def finalize(self):
611635
if self.next_single_filename:
@@ -627,11 +651,7 @@ def finalize(self):
627651

628652
def display_summary(self):
629653
duration = time.perf_counter() - self.start_time
630-
first_runtests = self.all_runtests[0]
631-
# the second runtests (re-run failed tests) disables forever,
632-
# use the first runtests
633-
forever = first_runtests.forever
634-
filtered = bool(self.ns.match_tests) or bool(self.ns.ignore_tests)
654+
filtered = bool(self.match_tests) or bool(self.ignore_tests)
635655

636656
# Total duration
637657
print()
@@ -655,8 +675,8 @@ def display_summary(self):
655675
self.environment_changed, self.run_no_tests]
656676
run = sum(map(len, all_tests))
657677
text = f'run={run}'
658-
if not forever:
659-
ntest = len(first_runtests.tests)
678+
if not self.first_runtests.forever:
679+
ntest = len(self.first_runtests.tests)
660680
text = f"{text}/{ntest}"
661681
if filtered:
662682
text = f"{text} (filtered)"
@@ -788,7 +808,7 @@ def main(self, tests: TestList | None = None):
788808

789809
self.fix_umask()
790810

791-
if ns.cleanup:
811+
if self.want_cleanup:
792812
self.cleanup()
793813
sys.exit(0)
794814

@@ -838,12 +858,12 @@ def get_exitcode(self):
838858
return exitcode
839859

840860
def action_run_tests(self):
841-
self.run_tests()
861+
runtests = self.run_tests()
842862
self.display_result()
843863

844864
need_rerun = self.need_rerun
845865
if self.ns.rerun and need_rerun:
846-
self.rerun_failed_tests(need_rerun)
866+
self.rerun_failed_tests(need_rerun, runtests)
847867

848868
self.display_summary()
849869
self.finalize()
@@ -854,16 +874,16 @@ def _main(self):
854874
run_tests_worker(self.ns.worker_args)
855875
return
856876

857-
if self.ns.wait:
877+
if self.want_wait:
858878
input("Press any key to continue...")
859879

860880
setup_tests(self.ns)
861881
self.find_tests()
862882

863883
exitcode = 0
864-
if self.ns.list_tests:
884+
if self.want_list_tests:
865885
self.list_tests()
866-
elif self.ns.list_cases:
886+
elif self.want_list_cases:
867887
self.list_cases()
868888
else:
869889
self.action_run_tests()

Lib/test/libregrtest/runtest.py

+5
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ class RunTests:
212212
rerun: bool = False
213213
forever: bool = False
214214

215+
def copy(self, **override):
216+
state = dataclasses.asdict(self)
217+
state.update(override)
218+
return RunTests(**state)
219+
215220
def get_match_tests(self, test_name) -> FilterTuple | None:
216221
if self.match_tests is not None:
217222
return self.match_tests.get(test_name, None)

Lib/test/test_regrtest.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ def list_regex(line_format, tests):
589589
def parse_random_seed(self, output):
590590
match = self.regex_search(r'Using random seed ([0-9]+)', output)
591591
randseed = int(match.group(1))
592-
self.assertTrue(0 <= randseed <= 10000000, randseed)
592+
self.assertTrue(0 <= randseed <= 100_000_000, randseed)
593593
return randseed
594594

595595
def run_command(self, args, input=None, exitcode=0, **kw):

0 commit comments

Comments
 (0)