Skip to content

Commit f5d2b19

Browse files
authored
Merge pull request #5069 from blueyed/cleanup-summary-to-terminal
cleanup: move terminal summary code to terminal plugin
2 parents 10fa66e + dde27a2 commit f5d2b19

File tree

5 files changed

+138
-160
lines changed

5 files changed

+138
-160
lines changed

changelog/5069.trivial.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The code for the short test summary in the terminal was moved to the terminal plugin.

src/_pytest/skipping.py

Lines changed: 0 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -183,128 +183,3 @@ def pytest_report_teststatus(report):
183183
return "xfailed", "x", "XFAIL"
184184
elif report.passed:
185185
return "xpassed", "X", "XPASS"
186-
187-
188-
# called by the terminalreporter instance/plugin
189-
190-
191-
def pytest_terminal_summary(terminalreporter):
192-
tr = terminalreporter
193-
if not tr.reportchars:
194-
return
195-
196-
lines = []
197-
for char in tr.reportchars:
198-
action = REPORTCHAR_ACTIONS.get(char, lambda tr, lines: None)
199-
action(terminalreporter, lines)
200-
201-
if lines:
202-
tr._tw.sep("=", "short test summary info")
203-
for line in lines:
204-
tr._tw.line(line)
205-
206-
207-
def show_simple(terminalreporter, lines, stat):
208-
failed = terminalreporter.stats.get(stat)
209-
if failed:
210-
config = terminalreporter.config
211-
for rep in failed:
212-
verbose_word = _get_report_str(config, rep)
213-
pos = _get_pos(config, rep)
214-
lines.append("%s %s" % (verbose_word, pos))
215-
216-
217-
def show_xfailed(terminalreporter, lines):
218-
xfailed = terminalreporter.stats.get("xfailed")
219-
if xfailed:
220-
config = terminalreporter.config
221-
for rep in xfailed:
222-
verbose_word = _get_report_str(config, rep)
223-
pos = _get_pos(config, rep)
224-
lines.append("%s %s" % (verbose_word, pos))
225-
reason = rep.wasxfail
226-
if reason:
227-
lines.append(" " + str(reason))
228-
229-
230-
def show_xpassed(terminalreporter, lines):
231-
xpassed = terminalreporter.stats.get("xpassed")
232-
if xpassed:
233-
config = terminalreporter.config
234-
for rep in xpassed:
235-
verbose_word = _get_report_str(config, rep)
236-
pos = _get_pos(config, rep)
237-
reason = rep.wasxfail
238-
lines.append("%s %s %s" % (verbose_word, pos, reason))
239-
240-
241-
def folded_skips(skipped):
242-
d = {}
243-
for event in skipped:
244-
key = event.longrepr
245-
assert len(key) == 3, (event, key)
246-
keywords = getattr(event, "keywords", {})
247-
# folding reports with global pytestmark variable
248-
# this is workaround, because for now we cannot identify the scope of a skip marker
249-
# TODO: revisit after marks scope would be fixed
250-
if (
251-
event.when == "setup"
252-
and "skip" in keywords
253-
and "pytestmark" not in keywords
254-
):
255-
key = (key[0], None, key[2])
256-
d.setdefault(key, []).append(event)
257-
values = []
258-
for key, events in d.items():
259-
values.append((len(events),) + key)
260-
return values
261-
262-
263-
def show_skipped(terminalreporter, lines):
264-
tr = terminalreporter
265-
skipped = tr.stats.get("skipped", [])
266-
if skipped:
267-
fskips = folded_skips(skipped)
268-
if fskips:
269-
verbose_word = _get_report_str(terminalreporter.config, report=skipped[0])
270-
for num, fspath, lineno, reason in fskips:
271-
if reason.startswith("Skipped: "):
272-
reason = reason[9:]
273-
if lineno is not None:
274-
lines.append(
275-
"%s [%d] %s:%d: %s"
276-
% (verbose_word, num, fspath, lineno + 1, reason)
277-
)
278-
else:
279-
lines.append("%s [%d] %s: %s" % (verbose_word, num, fspath, reason))
280-
281-
282-
def shower(stat):
283-
def show_(terminalreporter, lines):
284-
return show_simple(terminalreporter, lines, stat)
285-
286-
return show_
287-
288-
289-
def _get_report_str(config, report):
290-
_category, _short, verbose = config.hook.pytest_report_teststatus(
291-
report=report, config=config
292-
)
293-
return verbose
294-
295-
296-
def _get_pos(config, rep):
297-
nodeid = config.cwd_relative_nodeid(rep.nodeid)
298-
return nodeid
299-
300-
301-
REPORTCHAR_ACTIONS = {
302-
"x": show_xfailed,
303-
"X": show_xpassed,
304-
"f": shower("failed"),
305-
"F": shower("failed"),
306-
"s": show_skipped,
307-
"S": show_skipped,
308-
"p": shower("passed"),
309-
"E": shower("error"),
310-
}

src/_pytest/terminal.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import platform
1212
import sys
1313
import time
14+
from functools import partial
1415

1516
import attr
1617
import pluggy
@@ -681,6 +682,7 @@ def pytest_terminal_summary(self):
681682
self.summary_failures()
682683
self.summary_warnings()
683684
yield
685+
self.short_test_summary()
684686
self.summary_passes()
685687
# Display any extra warnings from teardown here (if any).
686688
self.summary_warnings()
@@ -876,6 +878,106 @@ def summary_stats(self):
876878
if self.verbosity == -1:
877879
self.write_line(msg, **markup)
878880

881+
def short_test_summary(self):
882+
if not self.reportchars:
883+
return
884+
885+
def show_simple(stat, lines):
886+
failed = self.stats.get(stat, [])
887+
for rep in failed:
888+
verbose_word = _get_report_str(self.config, rep)
889+
pos = _get_pos(self.config, rep)
890+
lines.append("%s %s" % (verbose_word, pos))
891+
892+
def show_xfailed(lines):
893+
xfailed = self.stats.get("xfailed", [])
894+
for rep in xfailed:
895+
verbose_word = _get_report_str(self.config, rep)
896+
pos = _get_pos(self.config, rep)
897+
lines.append("%s %s" % (verbose_word, pos))
898+
reason = rep.wasxfail
899+
if reason:
900+
lines.append(" " + str(reason))
901+
902+
def show_xpassed(lines):
903+
xpassed = self.stats.get("xpassed", [])
904+
for rep in xpassed:
905+
verbose_word = _get_report_str(self.config, rep)
906+
pos = _get_pos(self.config, rep)
907+
reason = rep.wasxfail
908+
lines.append("%s %s %s" % (verbose_word, pos, reason))
909+
910+
def show_skipped(lines):
911+
skipped = self.stats.get("skipped", [])
912+
fskips = _folded_skips(skipped) if skipped else []
913+
if not fskips:
914+
return
915+
verbose_word = _get_report_str(self.config, report=skipped[0])
916+
for num, fspath, lineno, reason in fskips:
917+
if reason.startswith("Skipped: "):
918+
reason = reason[9:]
919+
if lineno is not None:
920+
lines.append(
921+
"%s [%d] %s:%d: %s"
922+
% (verbose_word, num, fspath, lineno + 1, reason)
923+
)
924+
else:
925+
lines.append("%s [%d] %s: %s" % (verbose_word, num, fspath, reason))
926+
927+
def _get_report_str(config, report):
928+
_category, _short, verbose = config.hook.pytest_report_teststatus(
929+
report=report, config=config
930+
)
931+
return verbose
932+
933+
def _get_pos(config, rep):
934+
nodeid = config.cwd_relative_nodeid(rep.nodeid)
935+
return nodeid
936+
937+
REPORTCHAR_ACTIONS = {
938+
"x": show_xfailed,
939+
"X": show_xpassed,
940+
"f": partial(show_simple, "failed"),
941+
"F": partial(show_simple, "failed"),
942+
"s": show_skipped,
943+
"S": show_skipped,
944+
"p": partial(show_simple, "passed"),
945+
"E": partial(show_simple, "error"),
946+
}
947+
948+
lines = []
949+
for char in self.reportchars:
950+
action = REPORTCHAR_ACTIONS.get(char)
951+
if action: # skipping e.g. "P" (passed with output) here.
952+
action(lines)
953+
954+
if lines:
955+
self.write_sep("=", "short test summary info")
956+
for line in lines:
957+
self.write_line(line)
958+
959+
960+
def _folded_skips(skipped):
961+
d = {}
962+
for event in skipped:
963+
key = event.longrepr
964+
assert len(key) == 3, (event, key)
965+
keywords = getattr(event, "keywords", {})
966+
# folding reports with global pytestmark variable
967+
# this is workaround, because for now we cannot identify the scope of a skip marker
968+
# TODO: revisit after marks scope would be fixed
969+
if (
970+
event.when == "setup"
971+
and "skip" in keywords
972+
and "pytestmark" not in keywords
973+
):
974+
key = (key[0], None, key[2])
975+
d.setdefault(key, []).append(event)
976+
values = []
977+
for key, events in d.items():
978+
values.append((len(events),) + key)
979+
return values
980+
879981

880982
def build_summary_stats_line(stats):
881983
known_types = (

testing/test_skipping.py

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import pytest
88
from _pytest.runner import runtestprotocol
9-
from _pytest.skipping import folded_skips
109
from _pytest.skipping import MarkEvaluator
1110
from _pytest.skipping import pytest_runtest_setup
1211

@@ -749,40 +748,6 @@ def test_though(self):
749748
result.stdout.fnmatch_lines(["*2 skipped*"])
750749

751750

752-
def test_skip_reasons_folding():
753-
path = "xyz"
754-
lineno = 3
755-
message = "justso"
756-
longrepr = (path, lineno, message)
757-
758-
class X(object):
759-
pass
760-
761-
ev1 = X()
762-
ev1.when = "execute"
763-
ev1.skipped = True
764-
ev1.longrepr = longrepr
765-
766-
ev2 = X()
767-
ev2.when = "execute"
768-
ev2.longrepr = longrepr
769-
ev2.skipped = True
770-
771-
# ev3 might be a collection report
772-
ev3 = X()
773-
ev3.when = "collect"
774-
ev3.longrepr = longrepr
775-
ev3.skipped = True
776-
777-
values = folded_skips([ev1, ev2, ev3])
778-
assert len(values) == 1
779-
num, fspath, lineno, reason = values[0]
780-
assert num == 3
781-
assert fspath == path
782-
assert lineno == lineno
783-
assert reason == message
784-
785-
786751
def test_skipped_reasons_functional(testdir):
787752
testdir.makepyfile(
788753
test_one="""

testing/test_terminal.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import pytest
1717
from _pytest.main import EXIT_NOTESTSCOLLECTED
1818
from _pytest.reports import BaseReport
19+
from _pytest.terminal import _folded_skips
1920
from _pytest.terminal import _plugin_nameversions
2021
from _pytest.terminal import build_summary_stats_line
2122
from _pytest.terminal import getreportopt
@@ -1524,3 +1525,37 @@ def test_xdist_normal(self, many_files, testdir, monkeypatch):
15241525
monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False)
15251526
output = testdir.runpytest("-n2")
15261527
output.stdout.re_match_lines([r"[\.E]{40} \s+ \[100%\]"])
1528+
1529+
1530+
def test_skip_reasons_folding():
1531+
path = "xyz"
1532+
lineno = 3
1533+
message = "justso"
1534+
longrepr = (path, lineno, message)
1535+
1536+
class X(object):
1537+
pass
1538+
1539+
ev1 = X()
1540+
ev1.when = "execute"
1541+
ev1.skipped = True
1542+
ev1.longrepr = longrepr
1543+
1544+
ev2 = X()
1545+
ev2.when = "execute"
1546+
ev2.longrepr = longrepr
1547+
ev2.skipped = True
1548+
1549+
# ev3 might be a collection report
1550+
ev3 = X()
1551+
ev3.when = "collect"
1552+
ev3.longrepr = longrepr
1553+
ev3.skipped = True
1554+
1555+
values = _folded_skips([ev1, ev2, ev3])
1556+
assert len(values) == 1
1557+
num, fspath, lineno, reason = values[0]
1558+
assert num == 3
1559+
assert fspath == path
1560+
assert lineno == lineno
1561+
assert reason == message

0 commit comments

Comments
 (0)