cleanup: move terminal summary code to terminal plugin
Fixes https://github.com/pytest-dev/pytest/issues/5067.
This commit is contained in:
		
							parent
							
								
									b549438423
								
							
						
					
					
						commit
						c70ecd49ca
					
				|  | @ -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"), | ||||
| } | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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=""" | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue