Skip to content

Commit f3aead8

Browse files
Merge pull request #1600 from nicoddemus/issue-1599-disable-cap-fixtures
Add disabled() method to capsys and capfd
2 parents 308396a + 72bf11c commit f3aead8

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434
* New ``pytest_make_parametrize_id`` hook.
3535
Thanks `@palaviv`_ for the PR.
3636

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

_pytest/capture.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55
from __future__ import with_statement
66

7+
import contextlib
78
import sys
89
import os
910
from tempfile import TemporaryFile
@@ -146,8 +147,8 @@ def pytest_keyboard_interrupt(self, excinfo):
146147
def pytest_internalerror(self, excinfo):
147148
self.reset_capturings()
148149

149-
def suspendcapture_item(self, item, when):
150-
out, err = self.suspendcapture()
150+
def suspendcapture_item(self, item, when, in_=False):
151+
out, err = self.suspendcapture(in_=in_)
151152
item.add_report_section(when, "stdout", out)
152153
item.add_report_section(when, "stderr", err)
153154

@@ -162,7 +163,7 @@ def capsys(request):
162163
"""
163164
if "capfd" in request._funcargs:
164165
raise request.raiseerror(error_capsysfderror)
165-
request.node._capfuncarg = c = CaptureFixture(SysCapture)
166+
request.node._capfuncarg = c = CaptureFixture(SysCapture, request)
166167
return c
167168

168169
@pytest.fixture
@@ -175,17 +176,18 @@ def capfd(request):
175176
request.raiseerror(error_capsysfderror)
176177
if not hasattr(os, 'dup'):
177178
pytest.skip("capfd funcarg needs os.dup")
178-
request.node._capfuncarg = c = CaptureFixture(FDCapture)
179+
request.node._capfuncarg = c = CaptureFixture(FDCapture, request)
179180
return c
180181

181182

182183
class CaptureFixture:
183-
def __init__(self, captureclass):
184+
def __init__(self, captureclass, request):
184185
self.captureclass = captureclass
186+
self.request = request
185187

186188
def _start(self):
187189
self._capture = MultiCapture(out=True, err=True, in_=False,
188-
Capture=self.captureclass)
190+
Capture=self.captureclass)
189191
self._capture.start_capturing()
190192

191193
def close(self):
@@ -200,6 +202,15 @@ def readouterr(self):
200202
except AttributeError:
201203
return self._outerr
202204

205+
@contextlib.contextmanager
206+
def disabled(self):
207+
capmanager = self.request.config.pluginmanager.getplugin('capturemanager')
208+
capmanager.suspendcapture_item(self.request.node, "call", in_=True)
209+
try:
210+
yield
211+
finally:
212+
capmanager.resumecapture()
213+
203214

204215
def safe_text_dupfile(f, mode, default_encoding="UTF8"):
205216
""" return a open text file object that's a duplicate of f on the

doc/en/capture.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,19 @@ same interface but allows to also capture output from
115115
libraries or subprocesses that directly write to operating
116116
system level output streams (FD1 and FD2).
117117

118+
119+
.. versionadded:: 2.10
120+
121+
To temporarily disable capture within a test, both ``capsys``
122+
and ``capfd`` have a ``disabled()`` method that can be used
123+
as a context manager, disabling capture inside the ``with`` block:
124+
125+
.. code-block:: python
126+
127+
def test_disabling_capturing(capsys):
128+
print('this output is captured')
129+
with capsys.disabled():
130+
print('output not captured, going directly to sys.stdout')
131+
print('this output is also captured')
132+
118133
.. include:: links.inc

testing/test_capture.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,22 @@ def test_log(capsys):
480480
result = testdir.runpytest_subprocess(p)
481481
assert 'closed' not in result.stderr.str()
482482

483+
@pytest.mark.parametrize('fixture', ['capsys', 'capfd'])
484+
def test_disabled_capture_fixture(self, testdir, fixture):
485+
testdir.makepyfile("""
486+
def test_disabled({fixture}):
487+
print('captured before')
488+
with {fixture}.disabled():
489+
print('while capture is disabled')
490+
print('captured after')
491+
""".format(fixture=fixture))
492+
result = testdir.runpytest_subprocess()
493+
result.stdout.fnmatch_lines("""
494+
*while capture is disabled*
495+
""")
496+
assert 'captured before' not in result.stdout.str()
497+
assert 'captured after' not in result.stdout.str()
498+
483499

484500
def test_setup_failure_does_not_kill_capturing(testdir):
485501
sub1 = testdir.mkpydir("sub1")

0 commit comments

Comments
 (0)