Improve quitting from pdb

Regarding tests: it merges ``test_pdb_interaction``,
``test_pdb_print_captured_stdout``, and
``test_pdb_print_captured_stderr`` into
``test_pdb_print_captured_stdout_and_stderr`` (clarity and performance,
especially since pexpect tests are slow).
This commit is contained in:
Daniel Hahler 2018-10-31 16:20:44 +01:00
parent 4947eb85c0
commit e69b1255d7
4 changed files with 85 additions and 62 deletions

View File

@ -0,0 +1,3 @@
Improve quitting from pdb, especially with ``--trace``.
Using ``q[quit]`` after ``pdb.set_trace()`` will quit pytest also.

View File

@ -118,6 +118,10 @@ class pytestPDB(object):
do_c = do_cont = do_continue
def set_quit(self):
super(_PdbWrapper, self).set_quit()
outcomes.exit("Quitting debugger")
def setup(self, f, tb):
"""Suspend on setup().
@ -210,8 +214,7 @@ def _enter_pdb(node, excinfo, rep):
tw.sep(">", "entering PDB")
tb = _postmortem_traceback(excinfo)
rep._pdbshown = True
if post_mortem(tb):
outcomes.exit("Quitting debugger")
post_mortem(tb)
return rep
@ -242,4 +245,5 @@ def post_mortem(t):
p = Pdb()
p.reset()
p.interaction(None, t)
return p.quitting
if p.quitting:
outcomes.exit("Quitting debugger")

View File

@ -49,13 +49,13 @@ class Failed(OutcomeException):
__module__ = "builtins"
class Exit(SystemExit):
class Exit(Exception):
""" raised for immediate program exits (no tracebacks/summaries)"""
def __init__(self, msg="unknown reason", returncode=None):
self.msg = msg
self.returncode = returncode
SystemExit.__init__(self, msg)
super(Exit, self).__init__(msg)
# exposed helper methods
@ -63,7 +63,7 @@ class Exit(SystemExit):
def exit(msg, returncode=None):
"""
Exit testing process as if SystemExit was triggered.
Exit testing process.
:param str msg: message to display upon exit.
:param int returncode: return code to be used when exiting pytest.

View File

@ -147,29 +147,6 @@ class TestPDB(object):
assert rep.failed
assert len(pdblist) == 1
def test_pdb_interaction(self, testdir):
p1 = testdir.makepyfile(
"""
def test_1():
i = 0
assert i == 1
def test_not_called_due_to_quit():
pass
"""
)
child = testdir.spawn_pytest("--pdb %s" % p1)
child.expect(".*def test_1")
child.expect(".*i = 0")
child.expect("Pdb")
child.sendeof()
rest = child.read().decode("utf8")
assert "= 1 failed in" in rest
assert "def test_1" not in rest
assert "Exit: Quitting debugger" in rest
assert "PDB continue (IO-capturing resumed)" not in rest
self.flush(child)
@staticmethod
def flush(child):
if platform.system() == "Darwin":
@ -214,40 +191,32 @@ class TestPDB(object):
child.sendeof()
self.flush(child)
def test_pdb_print_captured_stdout(self, testdir):
p1 = testdir.makepyfile(
"""
def test_1():
print("get\\x20rekt")
assert False
"""
)
child = testdir.spawn_pytest("--pdb %s" % p1)
child.expect("captured stdout")
child.expect("get rekt")
child.expect("Pdb")
child.sendeof()
rest = child.read().decode("utf8")
assert "1 failed" in rest
assert "get rekt" not in rest
self.flush(child)
def test_pdb_print_captured_stderr(self, testdir):
def test_pdb_print_captured_stdout_and_stderr(self, testdir):
p1 = testdir.makepyfile(
"""
def test_1():
import sys
sys.stderr.write("get\\x20rekt")
print("get\\x20rekt")
assert False
def test_not_called_due_to_quit():
pass
"""
)
child = testdir.spawn_pytest("--pdb %s" % p1)
child.expect("captured stdout")
child.expect("get rekt")
child.expect("captured stderr")
child.expect("get rekt")
child.expect("traceback")
child.expect("def test_1")
child.expect("Pdb")
child.sendeof()
rest = child.read().decode("utf8")
assert "1 failed" in rest
assert "Exit: Quitting debugger" in rest
assert "= 1 failed in" in rest
assert "def test_1" not in rest
assert "get rekt" not in rest
self.flush(child)
@ -375,15 +344,17 @@ class TestPDB(object):
i = 0
print("hello17")
pytest.set_trace()
x = 3
i == 1
assert 0
"""
)
child = testdir.spawn_pytest(str(p1))
child.expect("test_1")
child.expect("x = 3")
child.expect(r"test_1\(\)")
child.expect("i == 1")
child.expect("Pdb")
child.sendeof()
child.sendline("c")
rest = child.read().decode("utf-8")
assert "AssertionError" in rest
assert "1 failed" in rest
assert "def test_1" in rest
assert "hello17" in rest # out is captured
@ -398,13 +369,14 @@ class TestPDB(object):
print("hello17")
pytest.set_trace(header="== my_header ==")
x = 3
assert 0
"""
)
child = testdir.spawn_pytest(str(p1))
child.expect("== my_header ==")
assert "PDB set_trace" not in child.before.decode()
child.expect("Pdb")
child.sendeof()
child.sendline("c")
rest = child.read().decode("utf-8")
assert "1 failed" in rest
assert "def test_1" in rest
@ -424,9 +396,9 @@ class TestPDB(object):
child.expect("Pdb")
child.sendeof()
rest = child.read().decode("utf8")
assert "1 failed" in rest
assert "no tests ran" in rest
assert "reading from stdin while output" not in rest
assert "BdbQuit" in rest
assert "BdbQuit" not in rest
self.flush(child)
def test_pdb_and_capsys(self, testdir):
@ -518,6 +490,7 @@ class TestPDB(object):
print("hello18")
pytest.set_trace()
x = 4
assert 0
"""
)
child = testdir.spawn_pytest(str(p1))
@ -530,11 +503,11 @@ class TestPDB(object):
child.expect(r"PDB set_trace \(IO-capturing turned off\)")
child.expect("x = 4")
child.expect("Pdb")
child.sendeof()
child.sendline("c")
child.expect("_ test_1 _")
child.expect("def test_1")
child.expect("Captured stdout call")
rest = child.read().decode("utf8")
assert "Captured stdout call" in rest
assert "hello17" in rest # out is captured
assert "hello18" in rest # out is captured
assert "1 failed" in rest
@ -795,7 +768,7 @@ class TestDebuggingBreakpoints(object):
child.expect("Pdb")
child.sendeof()
rest = child.read().decode("utf8")
assert "1 failed" in rest
assert "Quitting debugger" in rest
assert "reading from stdin while output" not in rest
TestPDB.flush(child)
@ -808,12 +781,13 @@ class TestDebuggingBreakpoints(object):
import pdb
def test_1():
pdb.set_trace()
assert 0
"""
)
child = testdir.spawn_pytest(str(p1))
child.expect("test_1")
child.expect("Pdb")
child.sendeof()
child.sendline("c")
rest = child.read().decode("utf8")
assert "1 failed" in rest
assert "reading from stdin while output" not in rest
@ -826,15 +800,29 @@ class TestTraceOption:
"""
def test_1():
assert True
def test_2():
pass
def test_3():
pass
"""
)
child = testdir.spawn_pytest("--trace " + str(p1))
child.expect("test_1")
child.expect("Pdb")
child.sendeof()
child.sendline("c")
child.expect("test_2")
child.expect("Pdb")
child.sendline("c")
child.expect("test_3")
child.expect("Pdb")
child.sendline("q")
child.expect_exact("Exit: Quitting debugger")
rest = child.read().decode("utf8")
assert "1 passed" in rest
assert "2 passed in" in rest
assert "reading from stdin while output" not in rest
assert "Exit: Quitting debugger" in child.before.decode("utf8")
TestPDB.flush(child)
@ -863,3 +851,31 @@ def test_trace_after_runpytest(testdir):
rest = child.read().decode("utf8")
TestPDB.flush(child)
assert child.exitstatus == 0, rest
def test_quit_with_swallowed_SystemExit(testdir):
"""Test that debugging's pytest_configure is re-entrant."""
p1 = testdir.makepyfile(
"""
def call_pdb_set_trace():
__import__('pdb').set_trace()
def test_1():
try:
call_pdb_set_trace()
except SystemExit:
pass
def test_2():
pass
"""
)
child = testdir.spawn_pytest(str(p1))
child.expect("Pdb")
child.sendline("q")
child.expect_exact("Exit: Quitting debugger")
rest = child.read().decode("utf8")
assert "no tests ran" in rest
TestPDB.flush(child)