Add disabled() method to capsys and capfd

Fix #1599
This commit is contained in:
Bruno Oliveira 2016-06-08 20:21:17 -03:00
parent 308396ae3c
commit 72bf11cbe9
4 changed files with 52 additions and 6 deletions

View File

@ -34,6 +34,10 @@
* New ``pytest_make_parametrize_id`` hook. * New ``pytest_make_parametrize_id`` hook.
Thanks `@palaviv`_ for the PR. Thanks `@palaviv`_ for the PR.
* ``capsys`` and ``capfd`` now have a ``disabled()`` method, which is a context manager
that can be used to temporarily disable capture within a test.
Thanks `@nicoddemus`_ for the PR.
* New cli flag ``--fixtures-per-test`` that shows which fixtures are being used * New cli flag ``--fixtures-per-test`` that shows which fixtures are being used
for each selected test item. Features doc strings of fixtures by default. for each selected test item. Features doc strings of fixtures by default.
Can also show where fixtures are defined if combined with ``-v``. Can also show where fixtures are defined if combined with ``-v``.

View File

@ -4,6 +4,7 @@ per-test stdout/stderr capturing mechanism.
""" """
from __future__ import with_statement from __future__ import with_statement
import contextlib
import sys import sys
import os import os
from tempfile import TemporaryFile from tempfile import TemporaryFile
@ -146,8 +147,8 @@ class CaptureManager:
def pytest_internalerror(self, excinfo): def pytest_internalerror(self, excinfo):
self.reset_capturings() self.reset_capturings()
def suspendcapture_item(self, item, when): def suspendcapture_item(self, item, when, in_=False):
out, err = self.suspendcapture() out, err = self.suspendcapture(in_=in_)
item.add_report_section(when, "stdout", out) item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err) item.add_report_section(when, "stderr", err)
@ -162,7 +163,7 @@ def capsys(request):
""" """
if "capfd" in request._funcargs: if "capfd" in request._funcargs:
raise request.raiseerror(error_capsysfderror) raise request.raiseerror(error_capsysfderror)
request.node._capfuncarg = c = CaptureFixture(SysCapture) request.node._capfuncarg = c = CaptureFixture(SysCapture, request)
return c return c
@pytest.fixture @pytest.fixture
@ -175,17 +176,18 @@ def capfd(request):
request.raiseerror(error_capsysfderror) request.raiseerror(error_capsysfderror)
if not hasattr(os, 'dup'): if not hasattr(os, 'dup'):
pytest.skip("capfd funcarg needs os.dup") pytest.skip("capfd funcarg needs os.dup")
request.node._capfuncarg = c = CaptureFixture(FDCapture) request.node._capfuncarg = c = CaptureFixture(FDCapture, request)
return c return c
class CaptureFixture: class CaptureFixture:
def __init__(self, captureclass): def __init__(self, captureclass, request):
self.captureclass = captureclass self.captureclass = captureclass
self.request = request
def _start(self): def _start(self):
self._capture = MultiCapture(out=True, err=True, in_=False, self._capture = MultiCapture(out=True, err=True, in_=False,
Capture=self.captureclass) Capture=self.captureclass)
self._capture.start_capturing() self._capture.start_capturing()
def close(self): def close(self):
@ -200,6 +202,15 @@ class CaptureFixture:
except AttributeError: except AttributeError:
return self._outerr return self._outerr
@contextlib.contextmanager
def disabled(self):
capmanager = self.request.config.pluginmanager.getplugin('capturemanager')
capmanager.suspendcapture_item(self.request.node, "call", in_=True)
try:
yield
finally:
capmanager.resumecapture()
def safe_text_dupfile(f, mode, default_encoding="UTF8"): def safe_text_dupfile(f, mode, default_encoding="UTF8"):
""" return a open text file object that's a duplicate of f on the """ return a open text file object that's a duplicate of f on the

View File

@ -115,4 +115,19 @@ same interface but allows to also capture output from
libraries or subprocesses that directly write to operating libraries or subprocesses that directly write to operating
system level output streams (FD1 and FD2). system level output streams (FD1 and FD2).
.. versionadded:: 2.10
To temporarily disable capture within a test, both ``capsys``
and ``capfd`` have a ``disabled()`` method that can be used
as a context manager, disabling capture inside the ``with`` block:
.. code-block:: python
def test_disabling_capturing(capsys):
print('this output is captured')
with capsys.disabled():
print('output not captured, going directly to sys.stdout')
print('this output is also captured')
.. include:: links.inc .. include:: links.inc

View File

@ -480,6 +480,22 @@ class TestCaptureFixture:
result = testdir.runpytest_subprocess(p) result = testdir.runpytest_subprocess(p)
assert 'closed' not in result.stderr.str() assert 'closed' not in result.stderr.str()
@pytest.mark.parametrize('fixture', ['capsys', 'capfd'])
def test_disabled_capture_fixture(self, testdir, fixture):
testdir.makepyfile("""
def test_disabled({fixture}):
print('captured before')
with {fixture}.disabled():
print('while capture is disabled')
print('captured after')
""".format(fixture=fixture))
result = testdir.runpytest_subprocess()
result.stdout.fnmatch_lines("""
*while capture is disabled*
""")
assert 'captured before' not in result.stdout.str()
assert 'captured after' not in result.stdout.str()
def test_setup_failure_does_not_kill_capturing(testdir): def test_setup_failure_does_not_kill_capturing(testdir):
sub1 = testdir.mkpydir("sub1") sub1 = testdir.mkpydir("sub1")