Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup: move terminal summary code to terminal plugin #5069

Merged
merged 5 commits into from
Apr 10, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -678,6 +679,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 @@ -873,6 +875,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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RonnyPfannschmidt is now the time to revisit this?

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