Skip to content

Commit d406786

Browse files
committed
pdb: handle capturing with fixtures only
1 parent c92021f commit d406786

File tree

3 files changed

+92
-6
lines changed

3 files changed

+92
-6
lines changed

src/_pytest/capture.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ def _getcapture(self, method):
107107
return MultiCapture(out=False, err=False, in_=False)
108108
raise ValueError("unknown capturing method: %r" % method) # pragma: no cover
109109

110+
def is_capturing(self):
111+
if self.is_globally_capturing():
112+
return "global"
113+
capture_fixture = getattr(self._current_item, "_capture_fixture", None)
114+
if capture_fixture is not None:
115+
return (
116+
"fixture %s" % self._current_item._capture_fixture.request.fixturename
117+
)
118+
return False
119+
110120
# Global capturing control
111121

112122
def is_globally_capturing(self):
@@ -134,6 +144,14 @@ def suspend_global_capture(self, in_=False):
134144
if cap is not None:
135145
cap.suspend_capturing(in_=in_)
136146

147+
def suspend(self, in_=False):
148+
self.suspend_fixture(self._current_item)
149+
self.suspend_global_capture(in_)
150+
151+
def resume(self):
152+
self.resume_global_capture()
153+
self.resume_fixture(self._current_item)
154+
137155
def read_global_capture(self):
138156
return self._global_capturing.readouterr()
139157

src/_pytest/debugging.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,30 @@ def _init_pdb(cls, *args, **kwargs):
109109
if cls._pluginmanager is not None:
110110
capman = cls._pluginmanager.getplugin("capturemanager")
111111
if capman:
112-
capman.suspend_global_capture(in_=True)
112+
capman.suspend(in_=True)
113113
tw = _pytest.config.create_terminal_writer(cls._config)
114114
tw.line()
115115
if cls._recursive_debug == 0:
116116
# Handle header similar to pdb.set_trace in py37+.
117117
header = kwargs.pop("header", None)
118118
if header is not None:
119119
tw.sep(">", header)
120-
elif capman and capman.is_globally_capturing():
121-
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
122120
else:
123-
tw.sep(">", "PDB set_trace")
121+
if capman:
122+
capturing = capman.is_capturing()
123+
else:
124+
capturing = False
125+
if capturing:
126+
if capturing == "global":
127+
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
128+
else:
129+
tw.sep(
130+
">",
131+
"PDB set_trace (IO-capturing turned off for %s)"
132+
% capturing,
133+
)
134+
else:
135+
tw.sep(">", "PDB set_trace")
124136

125137
class _PdbWrapper(cls._pdb_cls, object):
126138
_pytest_capman = capman
@@ -138,11 +150,18 @@ def do_continue(self, arg):
138150
tw = _pytest.config.create_terminal_writer(cls._config)
139151
tw.line()
140152
if cls._recursive_debug == 0:
141-
if self._pytest_capman.is_globally_capturing():
153+
capturing = self._pytest_capman.is_capturing()
154+
if capturing == "global":
142155
tw.sep(">", "PDB continue (IO-capturing resumed)")
156+
elif capturing:
157+
tw.sep(
158+
">",
159+
"PDB continue (IO-capturing resumed for %s)"
160+
% capturing,
161+
)
143162
else:
144163
tw.sep(">", "PDB continue")
145-
self._pytest_capman.resume_global_capture()
164+
self._pytest_capman.resume()
146165
cls._pluginmanager.hook.pytest_leave_pdb(
147166
config=cls._config, pdb=self
148167
)

testing/test_pdb.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,3 +970,52 @@ def test_2():
970970
rest = child.read().decode("utf8")
971971
assert "no tests ran" in rest
972972
TestPDB.flush(child)
973+
974+
975+
@pytest.mark.parametrize("fixture", ("capfd", "capsys"))
976+
def test_pdb_suspends_fixture_capturing(testdir, fixture):
977+
"""Using "-s" with pytest should suspend/resume fixture capturing."""
978+
p1 = testdir.makepyfile(
979+
"""
980+
def test_inner({fixture}):
981+
import sys
982+
983+
print("out_inner_before")
984+
sys.stderr.write("err_inner_before\\n")
985+
986+
__import__("pdb").set_trace()
987+
988+
print("out_inner_after")
989+
sys.stderr.write("err_inner_after\\n")
990+
991+
out, err = {fixture}.readouterr()
992+
assert out =="out_inner_before\\nout_inner_after\\n"
993+
assert err =="err_inner_before\\nerr_inner_after\\n"
994+
""".format(
995+
fixture=fixture
996+
)
997+
)
998+
999+
child = testdir.spawn_pytest(str(p1) + " -s")
1000+
1001+
child.expect("Pdb")
1002+
before = child.before.decode("utf8")
1003+
assert (
1004+
"> PDB set_trace (IO-capturing turned off for fixture %s) >" % (fixture)
1005+
in before
1006+
)
1007+
1008+
# Test that capturing is really suspended.
1009+
child.sendline("p 40 + 2")
1010+
child.expect("Pdb")
1011+
assert "\r\n42\r\n" in child.before.decode("utf8")
1012+
1013+
child.sendline("c")
1014+
rest = child.read().decode("utf8")
1015+
assert "out_inner" not in rest
1016+
assert "err_inner" not in rest
1017+
1018+
TestPDB.flush(child)
1019+
assert child.exitstatus == 0
1020+
assert "= 1 passed in " in rest
1021+
assert "> PDB continue (IO-capturing resumed for fixture %s) >" % (fixture) in rest

0 commit comments

Comments
 (0)