Skip to content

Commit 1265ec5

Browse files
committed
bump libregrtest
Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
1 parent 55b066d commit 1265ec5

27 files changed

+4376
-1558
lines changed

Lib/test/libregrtest/__init__.py

-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +0,0 @@
1-
# We import importlib *ASAP* in order to test #15386
2-
import importlib
3-
4-
from test.libregrtest.cmdline import _parse_args, RESOURCE_NAMES, ALL_RESOURCES
5-
from test.libregrtest.main import main

Lib/test/libregrtest/cmdline.py

+205-56
Large diffs are not rendered by default.

Lib/test/libregrtest/filter.py

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import itertools
2+
import operator
3+
import re
4+
5+
6+
# By default, don't filter tests
7+
_test_matchers = ()
8+
_test_patterns = ()
9+
10+
11+
def match_test(test):
12+
# Function used by support.run_unittest() and regrtest --list-cases
13+
result = False
14+
for matcher, result in reversed(_test_matchers):
15+
if matcher(test.id()):
16+
return result
17+
return not result
18+
19+
20+
def _is_full_match_test(pattern):
21+
# If a pattern contains at least one dot, it's considered
22+
# as a full test identifier.
23+
# Example: 'test.test_os.FileTests.test_access'.
24+
#
25+
# ignore patterns which contain fnmatch patterns: '*', '?', '[...]'
26+
# or '[!...]'. For example, ignore 'test_access*'.
27+
return ('.' in pattern) and (not re.search(r'[?*\[\]]', pattern))
28+
29+
30+
def get_match_tests():
31+
global _test_patterns
32+
return _test_patterns
33+
34+
35+
def set_match_tests(patterns):
36+
global _test_matchers, _test_patterns
37+
38+
if not patterns:
39+
_test_matchers = ()
40+
_test_patterns = ()
41+
else:
42+
itemgetter = operator.itemgetter
43+
patterns = tuple(patterns)
44+
if patterns != _test_patterns:
45+
_test_matchers = [
46+
(_compile_match_function(map(itemgetter(0), it)), result)
47+
for result, it in itertools.groupby(patterns, itemgetter(1))
48+
]
49+
_test_patterns = patterns
50+
51+
52+
def _compile_match_function(patterns):
53+
patterns = list(patterns)
54+
55+
if all(map(_is_full_match_test, patterns)):
56+
# Simple case: all patterns are full test identifier.
57+
# The test.bisect_cmd utility only uses such full test identifiers.
58+
return set(patterns).__contains__
59+
else:
60+
import fnmatch
61+
regex = '|'.join(map(fnmatch.translate, patterns))
62+
# The search *is* case sensitive on purpose:
63+
# don't use flags=re.IGNORECASE
64+
regex_match = re.compile(regex).match
65+
66+
def match_test_regex(test_id, regex_match=regex_match):
67+
if regex_match(test_id):
68+
# The regex matches the whole identifier, for example
69+
# 'test.test_os.FileTests.test_access'.
70+
return True
71+
else:
72+
# Try to match parts of the test identifier.
73+
# For example, split 'test.test_os.FileTests.test_access'
74+
# into: 'test', 'test_os', 'FileTests' and 'test_access'.
75+
return any(map(regex_match, test_id.split(".")))
76+
77+
return match_test_regex

Lib/test/libregrtest/findtests.py

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

Lib/test/libregrtest/logger.py

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import os
2+
import time
3+
4+
from test.support import MS_WINDOWS
5+
from .results import TestResults
6+
from .runtests import RunTests
7+
from .utils import print_warning
8+
9+
if MS_WINDOWS:
10+
from .win_utils import WindowsLoadTracker
11+
12+
13+
class Logger:
14+
def __init__(self, results: TestResults, quiet: bool, pgo: bool):
15+
self.start_time = time.perf_counter()
16+
self.test_count_text = ''
17+
self.test_count_width = 3
18+
self.win_load_tracker: WindowsLoadTracker | None = None
19+
self._results: TestResults = results
20+
self._quiet: bool = quiet
21+
self._pgo: bool = pgo
22+
23+
def log(self, line: str = '') -> None:
24+
empty = not line
25+
26+
# add the system load prefix: "load avg: 1.80 "
27+
load_avg = self.get_load_avg()
28+
if load_avg is not None:
29+
line = f"load avg: {load_avg:.2f} {line}"
30+
31+
# add the timestamp prefix: "0:01:05 "
32+
log_time = time.perf_counter() - self.start_time
33+
34+
mins, secs = divmod(int(log_time), 60)
35+
hours, mins = divmod(mins, 60)
36+
formatted_log_time = "%d:%02d:%02d" % (hours, mins, secs)
37+
38+
line = f"{formatted_log_time} {line}"
39+
if empty:
40+
line = line[:-1]
41+
42+
print(line, flush=True)
43+
44+
def get_load_avg(self) -> float | None:
45+
if hasattr(os, 'getloadavg'):
46+
try:
47+
return os.getloadavg()[0]
48+
except OSError:
49+
pass
50+
if self.win_load_tracker is not None:
51+
return self.win_load_tracker.getloadavg()
52+
return None
53+
54+
def display_progress(self, test_index: int, text: str) -> None:
55+
if self._quiet:
56+
return
57+
results = self._results
58+
59+
# "[ 51/405/1] test_tcl passed"
60+
line = f"{test_index:{self.test_count_width}}{self.test_count_text}"
61+
fails = len(results.bad) + len(results.env_changed)
62+
if fails and not self._pgo:
63+
line = f"{line}/{fails}"
64+
self.log(f"[{line}] {text}")
65+
66+
def set_tests(self, runtests: RunTests) -> None:
67+
if runtests.forever:
68+
self.test_count_text = ''
69+
self.test_count_width = 3
70+
else:
71+
self.test_count_text = '/{}'.format(len(runtests.tests))
72+
self.test_count_width = len(self.test_count_text) - 1
73+
74+
def start_load_tracker(self) -> None:
75+
if not MS_WINDOWS:
76+
return
77+
78+
try:
79+
self.win_load_tracker = WindowsLoadTracker()
80+
except PermissionError as error:
81+
# Standard accounts may not have access to the performance
82+
# counters.
83+
print_warning(f'Failed to create WindowsLoadTracker: {error}')
84+
85+
def stop_load_tracker(self) -> None:
86+
if self.win_load_tracker is None:
87+
return
88+
self.win_load_tracker.close()
89+
self.win_load_tracker = None

0 commit comments

Comments
 (0)