Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/4908.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The ``pytest_enter_pdb`` hook gets called with post-mortem (``--pdb``).
9 changes: 5 additions & 4 deletions src/_pytest/capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,7 @@ def __init__(self, captureclass, request):
self._captured_err = self.captureclass.EMPTY_BUFFER

def _start(self):
# Start if not started yet
if getattr(self, "_capture", None) is None:
if self._capture is None:
self._capture = MultiCapture(
out=True, err=True, in_=False, Capture=self.captureclass
)
Expand Down Expand Up @@ -389,11 +388,13 @@ def readouterr(self):

def _suspend(self):
"""Suspends this fixture's own capturing temporarily."""
self._capture.suspend_capturing()
if self._capture is not None:
self._capture.suspend_capturing()

def _resume(self):
"""Resumes this fixture's own capturing temporarily."""
self._capture.resume_capturing()
if self._capture is not None:
self._capture.resume_capturing()

@contextlib.contextmanager
def disabled(self):
Expand Down
27 changes: 12 additions & 15 deletions src/_pytest/debugging.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,17 @@ def setup(self, f, tb):
self._pytest_capman.suspend_global_capture(in_=True)
return ret

def get_stack(self, f, t):
stack, i = super(PytestPdbWrapper, self).get_stack(f, t)
if f is None:
# Find last non-hidden frame.
i = max(0, len(stack) - 1)
while i and stack[i][0].f_locals.get(
"__tracebackhide__", False
):
i -= 1
return stack, i

_pdb = PytestPdbWrapper(**kwargs)
cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config, pdb=_pdb)
else:
Expand Down Expand Up @@ -298,22 +309,8 @@ def _postmortem_traceback(excinfo):
return excinfo._excinfo[2]


def _find_last_non_hidden_frame(stack):
i = max(0, len(stack) - 1)
while i and stack[i][0].f_locals.get("__tracebackhide__", False):
i -= 1
return i


def post_mortem(t):
class Pdb(pytestPDB._pdb_cls, object):
def get_stack(self, f, t):
stack, i = super(Pdb, self).get_stack(f, t)
if f is None:
i = _find_last_non_hidden_frame(stack)
return stack, i

p = Pdb()
p = pytestPDB._init_pdb()
p.reset()
p.interaction(None, t)
if p.quitting:
Expand Down
20 changes: 15 additions & 5 deletions testing/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,8 @@ def test_pdb_collection_failure_is_shown(self, testdir):
["E NameError: *xxx*", "*! *Exit: Quitting debugger !*"] # due to EOF
)

def test_enter_leave_pdb_hooks_are_called(self, testdir):
@pytest.mark.parametrize("post_mortem", (False, True))
def test_enter_leave_pdb_hooks_are_called(self, post_mortem, testdir):
testdir.makeconftest(
"""
mypdb = None
Expand Down Expand Up @@ -773,16 +774,25 @@ def pytest_leave_pdb(config, pdb):
"""
import pytest

def test_foo():
def test_set_trace():
pytest.set_trace()
assert 0

def test_post_mortem():
assert 0
"""
)
child = testdir.spawn_pytest(str(p1))
if post_mortem:
child = testdir.spawn_pytest(str(p1) + " --pdb -s -k test_post_mortem")
else:
child = testdir.spawn_pytest(str(p1) + " -k test_set_trace")
child.expect("enter_pdb_hook")
child.sendline("c")
child.expect(r"PDB continue \(IO-capturing resumed\)")
child.expect("Captured stdout call")
if post_mortem:
child.expect(r"PDB continue")
else:
child.expect(r"PDB continue \(IO-capturing resumed\)")
child.expect("Captured stdout call")
rest = child.read().decode("utf8")
assert "leave_pdb_hook" in rest
assert "1 failed" in rest
Expand Down