Skip to content

Commit 8efbefb

Browse files
authored
New --xfail-tb flag (#12280)
Fix #12231
1 parent 4080459 commit 8efbefb

File tree

3 files changed

+83
-34
lines changed

3 files changed

+83
-34
lines changed

changelog/12231.feature.rst

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Added `--xfail-tb` flag, which turns on traceback output for XFAIL results.
2+
3+
* If the `--xfail-tb` flag is not sent, tracebacks for XFAIL results are NOT shown.
4+
* The style of traceback for XFAIL is set with `--tb`, and can be `auto|long|short|line|native|no`.
5+
* Note: Even if you have `--xfail-tb` set, you won't see them if `--tb=no`.
6+
7+
Some history:
8+
9+
With pytest 8.0, `-rx` or `-ra` would not only turn on summary reports for xfail, but also report the tracebacks for xfail results. This caused issues with some projects that utilize xfail, but don't want to see all of the xfail tracebacks.
10+
11+
This change detaches xfail tracebacks from `-rx`, and now we turn on xfail tracebacks with `--xfail-tb`. With this, the default `-rx`/ `-ra` behavior is identical to pre-8.0 with respect to xfail tracebacks. While this is a behavior change, it brings default behavior back to pre-8.0.0 behavior, which ultimately was considered the better course of action.

src/_pytest/terminal.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ def pytest_addoption(parser: Parser) -> None:
216216
choices=["auto", "long", "short", "no", "line", "native"],
217217
help="Traceback print mode (auto/long/short/line/native/no)",
218218
)
219+
group._addoption(
220+
"--xfail-tb",
221+
action="store_true",
222+
dest="xfail_tb",
223+
default=False,
224+
help="Show tracebacks for xfail (as long as --tb != no)",
225+
)
219226
group._addoption(
220227
"--show-capture",
221228
action="store",
@@ -1086,21 +1093,29 @@ def print_teardown_sections(self, rep: TestReport) -> None:
10861093
self._tw.line(content)
10871094

10881095
def summary_failures(self) -> None:
1089-
self.summary_failures_combined("failed", "FAILURES")
1096+
style = self.config.option.tbstyle
1097+
self.summary_failures_combined("failed", "FAILURES", style=style)
10901098

10911099
def summary_xfailures(self) -> None:
1092-
self.summary_failures_combined("xfailed", "XFAILURES", "x")
1100+
show_tb = self.config.option.xfail_tb
1101+
style = self.config.option.tbstyle if show_tb else "no"
1102+
self.summary_failures_combined("xfailed", "XFAILURES", style=style)
10931103

10941104
def summary_failures_combined(
1095-
self, which_reports: str, sep_title: str, needed_opt: Optional[str] = None
1105+
self,
1106+
which_reports: str,
1107+
sep_title: str,
1108+
*,
1109+
style: str,
1110+
needed_opt: Optional[str] = None,
10961111
) -> None:
1097-
if self.config.option.tbstyle != "no":
1112+
if style != "no":
10981113
if not needed_opt or self.hasopt(needed_opt):
10991114
reports: List[BaseReport] = self.getreports(which_reports)
11001115
if not reports:
11011116
return
11021117
self.write_sep("=", sep_title)
1103-
if self.config.option.tbstyle == "line":
1118+
if style == "line":
11041119
for rep in reports:
11051120
line = self._getcrashline(rep)
11061121
self.write_line(line)

testing/test_terminal.py

+52-29
Original file line numberDiff line numberDiff line change
@@ -2909,54 +2909,77 @@ def test_xfail_reason():
29092909
assert result.stdout.lines.count(expect2) == 1
29102910

29112911

2912-
def test_summary_xfail_tb(pytester: Pytester) -> None:
2913-
pytester.makepyfile(
2912+
@pytest.fixture()
2913+
def xfail_testfile(pytester: Pytester) -> Path:
2914+
return pytester.makepyfile(
29142915
"""
29152916
import pytest
29162917
2917-
@pytest.mark.xfail
2918-
def test_xfail():
2918+
def test_fail():
29192919
a, b = 1, 2
29202920
assert a == b
2921+
2922+
@pytest.mark.xfail
2923+
def test_xfail():
2924+
c, d = 3, 4
2925+
assert c == d
29212926
"""
29222927
)
2923-
result = pytester.runpytest("-rx")
2928+
2929+
2930+
def test_xfail_tb_default(xfail_testfile, pytester: Pytester) -> None:
2931+
result = pytester.runpytest(xfail_testfile)
2932+
2933+
# test_fail, show traceback
29242934
result.stdout.fnmatch_lines(
29252935
[
2936+
"*= FAILURES =*",
2937+
"*_ test_fail _*",
2938+
"*def test_fail():*",
2939+
"* a, b = 1, 2*",
2940+
"*> assert a == b*",
2941+
"*E assert 1 == 2*",
2942+
]
2943+
)
2944+
2945+
# test_xfail, don't show traceback
2946+
result.stdout.no_fnmatch_line("*= XFAILURES =*")
2947+
2948+
2949+
def test_xfail_tb_true(xfail_testfile, pytester: Pytester) -> None:
2950+
result = pytester.runpytest(xfail_testfile, "--xfail-tb")
2951+
2952+
# both test_fail and test_xfail, show traceback
2953+
result.stdout.fnmatch_lines(
2954+
[
2955+
"*= FAILURES =*",
2956+
"*_ test_fail _*",
2957+
"*def test_fail():*",
2958+
"* a, b = 1, 2*",
2959+
"*> assert a == b*",
2960+
"*E assert 1 == 2*",
29262961
"*= XFAILURES =*",
29272962
"*_ test_xfail _*",
2928-
"* @pytest.mark.xfail*",
2929-
"* def test_xfail():*",
2930-
"* a, b = 1, 2*",
2931-
"> *assert a == b*",
2932-
"E *assert 1 == 2*",
2933-
"test_summary_xfail_tb.py:6: AssertionError*",
2934-
"*= short test summary info =*",
2935-
"XFAIL test_summary_xfail_tb.py::test_xfail",
2936-
"*= 1 xfailed in * =*",
2963+
"*def test_xfail():*",
2964+
"* c, d = 3, 4*",
2965+
"*> assert c == d*",
2966+
"*E assert 3 == 4*",
2967+
"*short test summary info*",
29372968
]
29382969
)
29392970

29402971

2941-
def test_xfail_tb_line(pytester: Pytester) -> None:
2942-
pytester.makepyfile(
2943-
"""
2944-
import pytest
2972+
def test_xfail_tb_line(xfail_testfile, pytester: Pytester) -> None:
2973+
result = pytester.runpytest(xfail_testfile, "--xfail-tb", "--tb=line")
29452974

2946-
@pytest.mark.xfail
2947-
def test_xfail():
2948-
a, b = 1, 2
2949-
assert a == b
2950-
"""
2951-
)
2952-
result = pytester.runpytest("-rx", "--tb=line")
2975+
# both test_fail and test_xfail, show line
29532976
result.stdout.fnmatch_lines(
29542977
[
2978+
"*= FAILURES =*",
2979+
"*test_xfail_tb_line.py:5: assert 1 == 2",
29552980
"*= XFAILURES =*",
2956-
"*test_xfail_tb_line.py:6: assert 1 == 2",
2957-
"*= short test summary info =*",
2958-
"XFAIL test_xfail_tb_line.py::test_xfail",
2959-
"*= 1 xfailed in * =*",
2981+
"*test_xfail_tb_line.py:10: assert 3 == 4",
2982+
"*short test summary info*",
29602983
]
29612984
)
29622985

0 commit comments

Comments
 (0)