pdb: handle quitting in post_mortem

`help quit` in pdb says:

> Quit from the debugger. The program being executed is aborted.

But pytest would continue with the next tests, often making it necessary
to kill the pytest process when using `--pdb` and trying to cancel the
tests using `KeyboardInterrupt` / `Ctrl-C`.
This commit is contained in:
Daniel Hahler 2018-10-13 16:49:30 +02:00
parent 27d2683a02
commit 86c7dcff68
2 changed files with 18 additions and 5 deletions

View File

@ -1,10 +1,12 @@
""" interactive debugging with PDB, the Python Debugger. """ """ interactive debugging with PDB, the Python Debugger. """
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import os
import pdb import pdb
import sys import sys
import os
from doctest import UnexpectedException from doctest import UnexpectedException
from _pytest import outcomes
from _pytest.config import hookimpl from _pytest.config import hookimpl
try: try:
@ -164,8 +166,9 @@ def _enter_pdb(node, excinfo, rep):
rep.toterminal(tw) rep.toterminal(tw)
tw.sep(">", "entering PDB") tw.sep(">", "entering PDB")
tb = _postmortem_traceback(excinfo) tb = _postmortem_traceback(excinfo)
post_mortem(tb)
rep._pdbshown = True rep._pdbshown = True
if post_mortem(tb):
outcomes.exit("Quitting debugger")
return rep return rep
@ -196,3 +199,4 @@ def post_mortem(t):
p = Pdb() p = Pdb()
p.reset() p.reset()
p.interaction(None, t) p.interaction(None, t)
return p.quitting

View File

@ -25,6 +25,8 @@ def custom_pdb_calls():
# install dummy debugger class and track which methods were called on it # install dummy debugger class and track which methods were called on it
class _CustomPdb(object): class _CustomPdb(object):
quitting = False
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
called.append("init") called.append("init")
@ -142,6 +144,9 @@ class TestPDB(object):
def test_1(): def test_1():
i = 0 i = 0
assert i == 1 assert i == 1
def test_not_called_due_to_quit():
pass
""" """
) )
child = testdir.spawn_pytest("--pdb %s" % p1) child = testdir.spawn_pytest("--pdb %s" % p1)
@ -150,8 +155,9 @@ class TestPDB(object):
child.expect("Pdb") child.expect("Pdb")
child.sendeof() child.sendeof()
rest = child.read().decode("utf8") rest = child.read().decode("utf8")
assert "1 failed" in rest assert "= 1 failed in" in rest
assert "def test_1" not in rest assert "def test_1" not in rest
assert "Exit: Quitting debugger" in rest
self.flush(child) self.flush(child)
@staticmethod @staticmethod
@ -321,7 +327,7 @@ class TestPDB(object):
child = testdir.spawn_pytest("--pdb %s" % p1) child = testdir.spawn_pytest("--pdb %s" % p1)
# child.expect(".*import pytest.*") # child.expect(".*import pytest.*")
child.expect("Pdb") child.expect("Pdb")
child.sendeof() child.sendline("c")
child.expect("1 error") child.expect("1 error")
self.flush(child) self.flush(child)
@ -376,6 +382,7 @@ class TestPDB(object):
rest = child.read().decode("utf8") rest = child.read().decode("utf8")
assert "1 failed" in rest assert "1 failed" in rest
assert "reading from stdin while output" not in rest assert "reading from stdin while output" not in rest
assert "BdbQuit" in rest
self.flush(child) self.flush(child)
def test_pdb_and_capsys(self, testdir): def test_pdb_and_capsys(self, testdir):
@ -518,7 +525,9 @@ class TestPDB(object):
def test_pdb_collection_failure_is_shown(self, testdir): def test_pdb_collection_failure_is_shown(self, testdir):
p1 = testdir.makepyfile("xxx") p1 = testdir.makepyfile("xxx")
result = testdir.runpytest_subprocess("--pdb", p1) result = testdir.runpytest_subprocess("--pdb", p1)
result.stdout.fnmatch_lines(["*NameError*xxx*", "*1 error*"]) result.stdout.fnmatch_lines(
["E NameError: *xxx*", "*! *Exit: Quitting debugger !*"] # due to EOF
)
def test_enter_pdb_hook_is_called(self, testdir): def test_enter_pdb_hook_is_called(self, testdir):
testdir.makeconftest( testdir.makeconftest(