diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py index 22acafbdd..3f488fad5 100644 --- a/src/_pytest/skipping.py +++ b/src/_pytest/skipping.py @@ -183,128 +183,3 @@ def pytest_report_teststatus(report): return "xfailed", "x", "XFAIL" elif report.passed: return "xpassed", "X", "XPASS" - - -# called by the terminalreporter instance/plugin - - -def pytest_terminal_summary(terminalreporter): - tr = terminalreporter - if not tr.reportchars: - return - - lines = [] - for char in tr.reportchars: - action = REPORTCHAR_ACTIONS.get(char, lambda tr, lines: None) - action(terminalreporter, lines) - - if lines: - tr._tw.sep("=", "short test summary info") - for line in lines: - tr._tw.line(line) - - -def show_simple(terminalreporter, lines, stat): - failed = terminalreporter.stats.get(stat) - if failed: - config = terminalreporter.config - for rep in failed: - verbose_word = _get_report_str(config, rep) - pos = _get_pos(config, rep) - lines.append("%s %s" % (verbose_word, pos)) - - -def show_xfailed(terminalreporter, lines): - xfailed = terminalreporter.stats.get("xfailed") - if xfailed: - config = terminalreporter.config - for rep in xfailed: - verbose_word = _get_report_str(config, rep) - pos = _get_pos(config, rep) - lines.append("%s %s" % (verbose_word, pos)) - reason = rep.wasxfail - if reason: - lines.append(" " + str(reason)) - - -def show_xpassed(terminalreporter, lines): - xpassed = terminalreporter.stats.get("xpassed") - if xpassed: - config = terminalreporter.config - for rep in xpassed: - verbose_word = _get_report_str(config, rep) - pos = _get_pos(config, rep) - reason = rep.wasxfail - lines.append("%s %s %s" % (verbose_word, pos, reason)) - - -def folded_skips(skipped): - d = {} - for event in skipped: - key = event.longrepr - assert len(key) == 3, (event, key) - keywords = getattr(event, "keywords", {}) - # folding reports with global pytestmark variable - # this is workaround, because for now we cannot identify the scope of a skip marker - # TODO: revisit after marks scope would be fixed - if ( - event.when == "setup" - and "skip" in keywords - and "pytestmark" not in keywords - ): - key = (key[0], None, key[2]) - d.setdefault(key, []).append(event) - values = [] - for key, events in d.items(): - values.append((len(events),) + key) - return values - - -def show_skipped(terminalreporter, lines): - tr = terminalreporter - skipped = tr.stats.get("skipped", []) - if skipped: - fskips = folded_skips(skipped) - if fskips: - verbose_word = _get_report_str(terminalreporter.config, report=skipped[0]) - for num, fspath, lineno, reason in fskips: - if reason.startswith("Skipped: "): - reason = reason[9:] - if lineno is not None: - lines.append( - "%s [%d] %s:%d: %s" - % (verbose_word, num, fspath, lineno + 1, reason) - ) - else: - lines.append("%s [%d] %s: %s" % (verbose_word, num, fspath, reason)) - - -def shower(stat): - def show_(terminalreporter, lines): - return show_simple(terminalreporter, lines, stat) - - return show_ - - -def _get_report_str(config, report): - _category, _short, verbose = config.hook.pytest_report_teststatus( - report=report, config=config - ) - return verbose - - -def _get_pos(config, rep): - nodeid = config.cwd_relative_nodeid(rep.nodeid) - return nodeid - - -REPORTCHAR_ACTIONS = { - "x": show_xfailed, - "X": show_xpassed, - "f": shower("failed"), - "F": shower("failed"), - "s": show_skipped, - "S": show_skipped, - "p": shower("passed"), - "E": shower("error"), -} diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 31c0da46d..8d6abb17a 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -874,6 +874,128 @@ class TerminalReporter(object): self.write_line(msg, **markup) +def pytest_terminal_summary(terminalreporter): + tr = terminalreporter + if not tr.reportchars: + return + + lines = [] + for char in tr.reportchars: + action = REPORTCHAR_ACTIONS.get(char, lambda tr, lines: None) + action(terminalreporter, lines) + + if lines: + tr._tw.sep("=", "short test summary info") + for line in lines: + tr._tw.line(line) + + +def show_simple(terminalreporter, lines, stat): + failed = terminalreporter.stats.get(stat) + if failed: + config = terminalreporter.config + for rep in failed: + verbose_word = _get_report_str(config, rep) + pos = _get_pos(config, rep) + lines.append("%s %s" % (verbose_word, pos)) + + +def show_xfailed(terminalreporter, lines): + xfailed = terminalreporter.stats.get("xfailed") + if xfailed: + config = terminalreporter.config + for rep in xfailed: + verbose_word = _get_report_str(config, rep) + pos = _get_pos(config, rep) + lines.append("%s %s" % (verbose_word, pos)) + reason = rep.wasxfail + if reason: + lines.append(" " + str(reason)) + + +def show_xpassed(terminalreporter, lines): + xpassed = terminalreporter.stats.get("xpassed") + if xpassed: + config = terminalreporter.config + for rep in xpassed: + verbose_word = _get_report_str(config, rep) + pos = _get_pos(config, rep) + reason = rep.wasxfail + lines.append("%s %s %s" % (verbose_word, pos, reason)) + + +def folded_skips(skipped): + d = {} + for event in skipped: + key = event.longrepr + assert len(key) == 3, (event, key) + keywords = getattr(event, "keywords", {}) + # folding reports with global pytestmark variable + # this is workaround, because for now we cannot identify the scope of a skip marker + # TODO: revisit after marks scope would be fixed + if ( + event.when == "setup" + and "skip" in keywords + and "pytestmark" not in keywords + ): + key = (key[0], None, key[2]) + d.setdefault(key, []).append(event) + values = [] + for key, events in d.items(): + values.append((len(events),) + key) + return values + + +def show_skipped(terminalreporter, lines): + tr = terminalreporter + skipped = tr.stats.get("skipped", []) + if skipped: + fskips = folded_skips(skipped) + if fskips: + verbose_word = _get_report_str(terminalreporter.config, report=skipped[0]) + for num, fspath, lineno, reason in fskips: + if reason.startswith("Skipped: "): + reason = reason[9:] + if lineno is not None: + lines.append( + "%s [%d] %s:%d: %s" + % (verbose_word, num, fspath, lineno + 1, reason) + ) + else: + lines.append("%s [%d] %s: %s" % (verbose_word, num, fspath, reason)) + + +def shower(stat): + def show_(terminalreporter, lines): + return show_simple(terminalreporter, lines, stat) + + return show_ + + +def _get_report_str(config, report): + _category, _short, verbose = config.hook.pytest_report_teststatus( + report=report, config=config + ) + return verbose + + +def _get_pos(config, rep): + nodeid = config.cwd_relative_nodeid(rep.nodeid) + return nodeid + + +REPORTCHAR_ACTIONS = { + "x": show_xfailed, + "X": show_xpassed, + "f": shower("failed"), + "F": shower("failed"), + "s": show_skipped, + "S": show_skipped, + "p": shower("passed"), + "E": shower("error"), +} + + def build_summary_stats_line(stats): known_types = ( "failed passed skipped deselected xfailed xpassed warnings error".split() diff --git a/testing/test_skipping.py b/testing/test_skipping.py index e5206a44e..cef0fe6ee 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -6,7 +6,6 @@ import sys import pytest from _pytest.runner import runtestprotocol -from _pytest.skipping import folded_skips from _pytest.skipping import MarkEvaluator from _pytest.skipping import pytest_runtest_setup @@ -749,40 +748,6 @@ def test_skipif_class(testdir): result.stdout.fnmatch_lines(["*2 skipped*"]) -def test_skip_reasons_folding(): - path = "xyz" - lineno = 3 - message = "justso" - longrepr = (path, lineno, message) - - class X(object): - pass - - ev1 = X() - ev1.when = "execute" - ev1.skipped = True - ev1.longrepr = longrepr - - ev2 = X() - ev2.when = "execute" - ev2.longrepr = longrepr - ev2.skipped = True - - # ev3 might be a collection report - ev3 = X() - ev3.when = "collect" - ev3.longrepr = longrepr - ev3.skipped = True - - values = folded_skips([ev1, ev2, ev3]) - assert len(values) == 1 - num, fspath, lineno, reason = values[0] - assert num == 3 - assert fspath == path - assert lineno == lineno - assert reason == message - - def test_skipped_reasons_functional(testdir): testdir.makepyfile( test_one=""" diff --git a/testing/test_terminal.py b/testing/test_terminal.py index d0fdce23e..888104bf3 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -18,6 +18,7 @@ from _pytest.main import EXIT_NOTESTSCOLLECTED from _pytest.reports import BaseReport from _pytest.terminal import _plugin_nameversions from _pytest.terminal import build_summary_stats_line +from _pytest.terminal import folded_skips from _pytest.terminal import getreportopt from _pytest.terminal import TerminalReporter @@ -1524,3 +1525,37 @@ class TestProgressWithTeardown(object): monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) output = testdir.runpytest("-n2") output.stdout.re_match_lines([r"[\.E]{40} \s+ \[100%\]"]) + + +def test_skip_reasons_folding(): + path = "xyz" + lineno = 3 + message = "justso" + longrepr = (path, lineno, message) + + class X(object): + pass + + ev1 = X() + ev1.when = "execute" + ev1.skipped = True + ev1.longrepr = longrepr + + ev2 = X() + ev2.when = "execute" + ev2.longrepr = longrepr + ev2.skipped = True + + # ev3 might be a collection report + ev3 = X() + ev3.when = "collect" + ev3.longrepr = longrepr + ev3.skipped = True + + values = folded_skips([ev1, ev2, ev3]) + assert len(values) == 1 + num, fspath, lineno, reason = values[0] + assert num == 3 + assert fspath == path + assert lineno == lineno + assert reason == message