remove externally setting and dealing with "item.outerr" from capturing in favor of a direct interface for adding reporting sections to items.

* * *
refactor makereport implementation to avoid recursion with __multicall__
This commit is contained in:
holger krekel 2014-03-14 12:49:34 +01:00
parent cde970be69
commit b47fdbe0a7
7 changed files with 43 additions and 34 deletions

View File

@ -151,8 +151,6 @@ class CaptureManager:
def resumecapture_item(self, item):
method = self._getmethod(item.config, item.fspath)
if not hasattr(item, 'outerr'):
item.outerr = ('', '') # we accumulate outerr on the item
return self.resumecapture(method)
def resumecapture(self, method=None):
@ -174,16 +172,10 @@ class CaptureManager:
self.deactivate_funcargs()
if hasattr(self, '_capturing'):
method = self._capturing
del self._capturing
cap = self._method2capture.get(method)
if cap is not None:
outerr = cap.suspend()
del self._capturing
if item:
outerr = (item.outerr[0] + outerr[0],
item.outerr[1] + outerr[1])
return outerr
if hasattr(item, 'outerr'):
return item.outerr
return cap.suspend()
return "", ""
def activate_funcargs(self, pyfuncitem):
@ -235,18 +227,14 @@ class CaptureManager:
self.suspendcapture()
@pytest.mark.tryfirst
def pytest_runtest_makereport(self, __multicall__, item, call):
def pytest_runtest_makereport(self, item, call):
funcarg_outerr = self.deactivate_funcargs()
rep = __multicall__.execute()
outerr = self.suspendcapture(item)
out, err = self.suspendcapture(item)
if funcarg_outerr is not None:
outerr = (outerr[0] + funcarg_outerr[0],
outerr[1] + funcarg_outerr[1])
addouterr(rep, outerr)
if not rep.passed or rep.when == "teardown":
outerr = ('', '')
item.outerr = outerr
return rep
out += funcarg_outerr[0]
err += funcarg_outerr[1]
item.add_report_section(call.when, "out", out)
item.add_report_section(call.when, "err", err)
error_capsysfderror = "cannot use capsys and capfd at the same time"

View File

@ -108,12 +108,14 @@ class LogXML(object):
))
def _write_captured_output(self, report):
sec = dict(report.sections)
for name in ('out', 'err'):
content = sec.get("Captured std%s" % name)
if content:
tag = getattr(Junit, 'system-'+name)
self.append(tag(bin_xml_escape(content)))
for capname in ('out', 'err'):
allcontent = ""
for name, content in report.get_sections("Captured std%s" %
capname):
allcontent += content
if allcontent:
tag = getattr(Junit, 'system-'+capname)
self.append(tag(bin_xml_escape(allcontent)))
def append(self, obj):
self.tests[-1].append(obj)

View File

@ -233,6 +233,7 @@ class Node(object):
# used for storing artificial fixturedefs for direct parametrization
self._name2pseudofixturedef = {}
#self.extrainit()
@property
@ -469,6 +470,14 @@ class Item(Node):
"""
nextitem = None
def __init__(self, name, parent=None, config=None, session=None):
super(Item, self).__init__(name, parent, config, session)
self._report_sections = []
def add_report_section(self, when, key, content):
if content:
self._report_sections.append((when, key, content))
def reportinfo(self):
return self.fspath, None, ""

View File

@ -35,8 +35,8 @@ class pytestPDB:
if item is not None:
capman = item.config.pluginmanager.getplugin("capturemanager")
out, err = capman.suspendcapture()
if hasattr(item, 'outerr'):
item.outerr = (item.outerr[0] + out, item.outerr[1] + err)
#if hasattr(item, 'outerr'):
# item.outerr = (item.outerr[0] + out, item.outerr[1] + err)
tw = py.io.TerminalWriter()
tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)")

View File

@ -178,6 +178,11 @@ class BaseReport(object):
except UnicodeEncodeError:
out.line("<unprintable longrepr>")
def get_sections(self, prefix):
for name, content in self.sections:
if name.startswith(prefix):
yield prefix, content
passed = property(lambda x: x.outcome == "passed")
failed = property(lambda x: x.outcome == "failed")
skipped = property(lambda x: x.outcome == "skipped")
@ -191,6 +196,7 @@ def pytest_runtest_makereport(item, call):
duration = call.stop-call.start
keywords = dict([(x,1) for x in item.keywords])
excinfo = call.excinfo
sections = []
if not call.excinfo:
outcome = "passed"
longrepr = None
@ -209,16 +215,18 @@ def pytest_runtest_makereport(item, call):
else: # exception in setup or teardown
longrepr = item._repr_failure_py(excinfo,
style=item.config.option.tbstyle)
for rwhen, key, content in item._report_sections:
sections.append(("Captured std%s %s" %(key, rwhen), content))
return TestReport(item.nodeid, item.location,
keywords, outcome, longrepr, when,
duration=duration)
sections, duration)
class TestReport(BaseReport):
""" Basic test report object (also used for setup and teardown calls if
they fail).
"""
def __init__(self, nodeid, location,
keywords, outcome, longrepr, when, sections=(), duration=0, **extra):
def __init__(self, nodeid, location, keywords, outcome,
longrepr, when, sections=(), duration=0, **extra):
#: normalized collection node id
self.nodeid = nodeid

View File

@ -282,9 +282,9 @@ class TestPerTestCapturing:
"====* FAILURES *====",
"____*____",
"*test_capturing_outerr.py:8: ValueError",
"*--- Captured stdout ---*",
"*--- Captured stdout *call*",
"1",
"*--- Captured stderr ---*",
"*--- Captured stderr *call*",
"2",
])

View File

@ -478,10 +478,12 @@ def test_unicode_issue368(testdir):
path = testdir.tmpdir.join("test.xml")
log = LogXML(str(path), None)
ustr = py.builtin._totext("ВНИ!", "utf-8")
class report:
from _pytest.runner import BaseReport
class Report(BaseReport):
longrepr = ustr
sections = []
nodeid = "something"
report = Report()
# hopefully this is not too brittle ...
log.pytest_sessionstart()