fix issue128 - show captured output when capsys/capfd are in use

This commit is contained in:
holger krekel 2012-06-03 21:01:27 +02:00
parent 971f96468c
commit 3f17784386
5 changed files with 58 additions and 15 deletions

View File

@ -1,3 +1,8 @@
Changes between 2.2.4 and 2.2.5.dev
-----------------------------------
- fix issue128: show captured output when capsys/capfd are used
Changes between 2.2.3 and 2.2.4 Changes between 2.2.3 and 2.2.4
----------------------------------- -----------------------------------

View File

@ -1,2 +1,2 @@
# #
__version__ = '2.2.4' __version__ = '2.2.5.dev1'

View File

@ -121,20 +121,21 @@ class CaptureManager:
def activate_funcargs(self, pyfuncitem): def activate_funcargs(self, pyfuncitem):
if not hasattr(pyfuncitem, 'funcargs'): if not hasattr(pyfuncitem, 'funcargs'):
return return
assert not hasattr(self, '_capturing_funcargs') assert not hasattr(self, '_capturing_funcarg')
self._capturing_funcargs = capturing_funcargs = [] capargs = []
for name, capfuncarg in pyfuncitem.funcargs.items(): for name, capfuncarg in pyfuncitem.funcargs.items():
if name in ('capsys', 'capfd'): if name in ('capsys', 'capfd'):
capturing_funcargs.append(capfuncarg) capargs.append(capfuncarg)
capfuncarg._start() if capargs:
self._capturing_funcarg = capargs[0]
self._capturing_funcarg._start()
def deactivate_funcargs(self): def deactivate_funcargs(self):
capturing_funcargs = getattr(self, '_capturing_funcargs', None) capturing_funcarg = getattr(self, '_capturing_funcarg', None)
if capturing_funcargs is not None: if capturing_funcarg:
while capturing_funcargs: outerr = capturing_funcarg._finalize()
capfuncarg = capturing_funcargs.pop() del self._capturing_funcarg
capfuncarg._finalize() return outerr
del self._capturing_funcargs
def pytest_make_collect_report(self, __multicall__, collector): def pytest_make_collect_report(self, __multicall__, collector):
method = self._getmethod(collector.config, collector.fspath) method = self._getmethod(collector.config, collector.fspath)
@ -169,9 +170,12 @@ class CaptureManager:
@pytest.mark.tryfirst @pytest.mark.tryfirst
def pytest_runtest_makereport(self, __multicall__, item, call): def pytest_runtest_makereport(self, __multicall__, item, call):
self.deactivate_funcargs() funcarg_outerr = self.deactivate_funcargs()
rep = __multicall__.execute() rep = __multicall__.execute()
outerr = self.suspendcapture(item) outerr = self.suspendcapture(item)
if funcarg_outerr is not None:
outerr = (outerr[0] + funcarg_outerr[0],
outerr[1] + funcarg_outerr[1])
if not rep.passed: if not rep.passed:
addouterr(rep, outerr) addouterr(rep, outerr)
if not rep.passed or rep.when == "teardown": if not rep.passed or rep.when == "teardown":
@ -179,11 +183,15 @@ class CaptureManager:
item.outerr = outerr item.outerr = outerr
return rep return rep
error_capsysfderror = "cannot use capsys and capfd at the same time"
def pytest_funcarg__capsys(request): def pytest_funcarg__capsys(request):
"""enables capturing of writes to sys.stdout/sys.stderr and makes """enables capturing of writes to sys.stdout/sys.stderr and makes
captured output available via ``capsys.readouterr()`` method calls captured output available via ``capsys.readouterr()`` method calls
which return a ``(out, err)`` tuple. which return a ``(out, err)`` tuple.
""" """
if "capfd" in request._funcargs:
raise request.LookupError(error_capsysfderror)
return CaptureFuncarg(py.io.StdCapture) return CaptureFuncarg(py.io.StdCapture)
def pytest_funcarg__capfd(request): def pytest_funcarg__capfd(request):
@ -191,8 +199,10 @@ def pytest_funcarg__capfd(request):
captured output available via ``capsys.readouterr()`` method calls captured output available via ``capsys.readouterr()`` method calls
which return a ``(out, err)`` tuple. which return a ``(out, err)`` tuple.
""" """
if "capsys" in request._funcargs:
raise request.LookupError(error_capsysfderror)
if not hasattr(os, 'dup'): if not hasattr(os, 'dup'):
py.test.skip("capfd funcarg needs os.dup") pytest.skip("capfd funcarg needs os.dup")
return CaptureFuncarg(py.io.StdCaptureFD) return CaptureFuncarg(py.io.StdCaptureFD)
class CaptureFuncarg: class CaptureFuncarg:
@ -204,8 +214,9 @@ class CaptureFuncarg:
def _finalize(self): def _finalize(self):
if hasattr(self, 'capture'): if hasattr(self, 'capture'):
self.capture.reset() outerr = self.capture.reset()
del self.capture del self.capture
return outerr
def readouterr(self): def readouterr(self):
return self.capture.readouterr() return self.capture.readouterr()

View File

@ -24,7 +24,7 @@ def main():
name='pytest', name='pytest',
description='py.test: simple powerful testing with Python', description='py.test: simple powerful testing with Python',
long_description = long_description, long_description = long_description,
version='2.2.4', version='2.2.5.dev1',
url='http://pytest.org', url='http://pytest.org',
license='MIT license', license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],

View File

@ -373,6 +373,33 @@ class TestCaptureFuncarg:
""") """)
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
def test_capsyscapfd(self, testdir):
p = testdir.makepyfile("""
def test_one(capsys, capfd):
pass
def test_two(capfd, capsys):
pass
""")
result = testdir.runpytest(p)
result.stdout.fnmatch_lines([
"*ERROR*setup*test_one*",
"*capsys*capfd*same*time*",
"*ERROR*setup*test_two*",
"*capsys*capfd*same*time*",
"*2 error*"])
@pytest.mark.parametrize("method", ["sys", "fd"])
def test_capture_is_represented_on_failure_issue128(self, testdir, method):
p = testdir.makepyfile("""
def test_hello(cap%s):
print ("xxx42xxx")
assert 0
""" % method)
result = testdir.runpytest(p)
result.stdout.fnmatch_lines([
"xxx42xxx",
])
@needsosdup @needsosdup
def test_stdfd_functional(self, testdir): def test_stdfd_functional(self, testdir):
reprec = testdir.inline_runsource(""" reprec = testdir.inline_runsource("""