Skip to content

Commit b0e9c5e

Browse files
committed
Personal review fixes, adjust output locaiton
1 parent e4d41bf commit b0e9c5e

5 files changed

Lines changed: 45 additions & 23 deletions

File tree

‎Lib/test/libregrtest/result.py‎

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ class TestResult:
108108
# short descriptions of how the test altered the execution environment
109109
env_changed_reasons: list[str] | None = None
110110

111+
# test file, set once the test module is imported
112+
filename: str | None = None
113+
111114
def is_failed(self, fail_env_changed: bool) -> bool:
112115
if self.state == State.ENV_CHANGED:
113116
return fail_env_changed
@@ -205,23 +208,24 @@ def format_github_summary(self, expand: bool) -> str:
205208
return "".join(f"{block}\n\n" for block in blocks)
206209

207210
def print_github_annotation(self, runtests: RunTests) -> None:
208-
"""Print github error annotation line for each failure."""
209-
if not (runtests.github_annotations
210-
and self.is_failed(runtests.fail_env_changed)):
211+
"""Annotate a failed test file without failed test cases."""
212+
if (not runtests.github_annotations
213+
or not self.is_failed(runtests.fail_env_changed)
214+
or self.failed_test_cases):
211215
return
212-
# Convert python import test name to relative file path.
213-
# Ex: "test.test_x.test_y" is test_x/test_y.py
214-
name = self.test_name.removeprefix("test.")
215-
path = pathlib.Path(findtestdir(runtests.test_dir), *name.split("."))
216-
filename = path.with_suffix(".py")
217-
if not filename.exists():
218-
filename = path / "__init__.py"
219-
annotations = self.failed_test_cases
220-
if not annotations:
221-
message = "\n".join([str(self), *(self.env_changed_reasons or ())])
222-
annotations = [(self.test_name, message)]
223-
for title, message in annotations:
224-
print_github_annotation(title, message, str(filename))
216+
filename = self.filename
217+
if not filename:
218+
# The worker crashed or timed out before reporting the test file:
219+
# convert python import test name to relative file path.
220+
# Ex: "test.test_x.test_y" is test_x/test_y.py
221+
name = self.test_name.removeprefix("test.")
222+
path = pathlib.Path(findtestdir(runtests.test_dir),
223+
*name.split("."))
224+
filename = path.with_suffix(".py")
225+
if not filename.exists():
226+
filename = path / "__init__.py"
227+
message = "\n".join([str(self), *(self.env_changed_reasons or ())])
228+
print_github_annotation(self.test_name, message, str(filename))
225229

226230
def set_env_changed(self, *reasons):
227231
if self.state is None or self.state == State.PASSED:

‎Lib/test/libregrtest/setup.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from .filter import set_match_tests
1414
from .runtests import RunTests
15+
lazy from .testresult import RegressionTestResult
1516
from .utils import (
1617
setup_unraisable_hook, setup_threading_excepthook,
1718
adjust_rlimit_nofile)
@@ -112,9 +113,9 @@ def setup_tests(runtests: RunTests) -> None:
112113

113114
set_match_tests(runtests.match_tests)
114115

116+
RegressionTestResult.GITHUB_ANNOTATIONS = runtests.github_annotations
115117
if runtests.use_junit:
116118
support.junit_xml_list = []
117-
from .testresult import RegressionTestResult
118119
RegressionTestResult.USE_XML = True
119120
else:
120121
support.junit_xml_list = None

‎Lib/test/libregrtest/single.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ def _load_run_test(result: TestResult, runtests: RunTests) -> None:
153153
test_name = result.test_name
154154
module_name = abs_module_name(test_name, runtests.test_dir)
155155
test_mod = importlib.import_module(module_name)
156+
result.filename = test_mod.__file__
156157

157158
if hasattr(test_mod, "test_main"):
158159
# https://github.com/python/cpython/issues/89392

‎Lib/test/libregrtest/testresult.py‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
import traceback
1010
import unittest
1111
from test import support
12-
from test.libregrtest.utils import sanitize_xml
12+
from test.libregrtest.utils import print_github_annotation, sanitize_xml
1313

1414
class RegressionTestResult(unittest.TextTestResult):
1515
USE_XML = False
16+
GITHUB_ANNOTATIONS = False
1617

1718
def __init__(self, stream, descriptions, verbosity):
1819
super().__init__(stream=stream, descriptions=descriptions,
@@ -130,6 +131,14 @@ def addUnexpectedSuccess(self, test):
130131
self._add_result(test, outcome='UNEXPECTED_SUCCESS')
131132
super().addUnexpectedSuccess(test)
132133

134+
def printErrorList(self, flavour, errors):
135+
for test, err in errors:
136+
super().printErrorList(flavour, [(test, err)])
137+
# Annotate just after the failure report, so that the annotation
138+
# links to the report in the job log
139+
if self.GITHUB_ANNOTATIONS:
140+
print_github_annotation(str(test), err, stream=self.stream)
141+
133142
def get_xml_element(self):
134143
if not self.USE_XML:
135144
raise ValueError("USE_XML is false")
@@ -146,6 +155,11 @@ def __init__(self, stream, buffer=False):
146155

147156
def run(self, test):
148157
test(self.result)
158+
# Failures are not reported in quiet mode: annotate them at the end
159+
if self.result.GITHUB_ANNOTATIONS:
160+
for test, err in self.result.errors + self.result.failures:
161+
print_github_annotation(str(test), err,
162+
stream=self.result.stream)
149163
return self.result
150164

151165
def get_test_runner_class(verbosity, buffer=False):

‎Lib/test/libregrtest/utils.py‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,19 +148,21 @@ def print_warning(msg: str) -> None:
148148
",": "%2C"})
149149

150150

151-
def print_github_annotation(title: str, message: str, filename: str) -> None:
151+
def print_github_annotation(title: str, message: str,
152+
filename: str | None = None,
153+
stream=None) -> None:
152154
"""Print a GitHub Actions error annotation for the failure."""
153-
if not filename:
154-
raise ValueError(f"missing filename to annotate {title!r}")
155155
message = decolor(message)
156156

157-
# Try to get a line number from backtrace.
157+
# Try to get a file + line number from backtrace.
158158
line = None
159159
if frames := re.findall(r'^ *File "(.*)", line (\d+)', message,
160160
re.MULTILINE):
161161
test_frames = [frame for frame in frames
162162
if pathlib.Path(frame[0]).name.startswith('test_')]
163163
filename, line = test_frames[-1] if test_frames else frames[0]
164+
if not filename:
165+
raise ValueError(f"missing filename to annotate {title!r}")
164166

165167
# Normalize stdlib path to be relative inside the repository checkout.
166168
path = pathlib.Path(filename)
@@ -175,7 +177,7 @@ def print_github_annotation(title: str, message: str, filename: str) -> None:
175177
props_text = ",".join(f"{key}={value.translate(GITHUB_ESCAPE_PROPERTY)}"
176178
for key, value in props.items() if value)
177179
print(f"::error {props_text}::{message.translate(GITHUB_ESCAPE_DATA)}",
178-
flush=True)
180+
file=stream, flush=True)
179181

180182

181183
def regrtest_unraisable_hook(unraisable) -> None:

0 commit comments

Comments
 (0)