Skip to content

Commit

Permalink
Merge pull request #5069 from blueyed/cleanup-summary-to-terminal
Browse files Browse the repository at this point in the history
cleanup: move terminal summary code to terminal plugin
  • Loading branch information
nicoddemus authored Apr 10, 2019
2 parents 10fa66e + dde27a2 commit f5d2b19
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 160 deletions.
1 change: 1 addition & 0 deletions changelog/5069.trivial.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The code for the short test summary in the terminal was moved to the terminal plugin.
125 changes: 0 additions & 125 deletions src/_pytest/skipping.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
102 changes: 102 additions & 0 deletions src/_pytest/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import platform
import sys
import time
from functools import partial

import attr
import pluggy
Expand Down Expand Up @@ -681,6 +682,7 @@ def pytest_terminal_summary(self):
self.summary_failures()
self.summary_warnings()
yield
self.short_test_summary()
self.summary_passes()
# Display any extra warnings from teardown here (if any).
self.summary_warnings()
Expand Down Expand Up @@ -876,6 +878,106 @@ def summary_stats(self):
if self.verbosity == -1:
self.write_line(msg, **markup)

def short_test_summary(self):
if not self.reportchars:
return

def show_simple(stat, lines):
failed = self.stats.get(stat, [])
for rep in failed:
verbose_word = _get_report_str(self.config, rep)
pos = _get_pos(self.config, rep)
lines.append("%s %s" % (verbose_word, pos))

def show_xfailed(lines):
xfailed = self.stats.get("xfailed", [])
for rep in xfailed:
verbose_word = _get_report_str(self.config, rep)
pos = _get_pos(self.config, rep)
lines.append("%s %s" % (verbose_word, pos))
reason = rep.wasxfail
if reason:
lines.append(" " + str(reason))

def show_xpassed(lines):
xpassed = self.stats.get("xpassed", [])
for rep in xpassed:
verbose_word = _get_report_str(self.config, rep)
pos = _get_pos(self.config, rep)
reason = rep.wasxfail
lines.append("%s %s %s" % (verbose_word, pos, reason))

def show_skipped(lines):
skipped = self.stats.get("skipped", [])
fskips = _folded_skips(skipped) if skipped else []
if not fskips:
return
verbose_word = _get_report_str(self.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 _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": partial(show_simple, "failed"),
"F": partial(show_simple, "failed"),
"s": show_skipped,
"S": show_skipped,
"p": partial(show_simple, "passed"),
"E": partial(show_simple, "error"),
}

lines = []
for char in self.reportchars:
action = REPORTCHAR_ACTIONS.get(char)
if action: # skipping e.g. "P" (passed with output) here.
action(lines)

if lines:
self.write_sep("=", "short test summary info")
for line in lines:
self.write_line(line)


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 build_summary_stats_line(stats):
known_types = (
Expand Down
35 changes: 0 additions & 35 deletions testing/test_skipping.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

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

Expand Down Expand Up @@ -749,40 +748,6 @@ def test_though(self):
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="""
Expand Down
35 changes: 35 additions & 0 deletions testing/test_terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import pytest
from _pytest.main import EXIT_NOTESTSCOLLECTED
from _pytest.reports import BaseReport
from _pytest.terminal import _folded_skips
from _pytest.terminal import _plugin_nameversions
from _pytest.terminal import build_summary_stats_line
from _pytest.terminal import getreportopt
Expand Down Expand Up @@ -1524,3 +1525,37 @@ def test_xdist_normal(self, many_files, testdir, monkeypatch):
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

0 comments on commit f5d2b19

Please sign in to comment.