Skip to content

Commit 47ba6fd

Browse files
committed
Handle quitting from pdb with --trace
This raises ``outcomes.exit`` via ``set_quit``, and ``post_mortem`` directly already. 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).
1 parent fc4aa27 commit 47ba6fd

File tree

3 files changed

+49
-57
lines changed

3 files changed

+49
-57
lines changed

changelog/4280.bugfix.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Handle quitting from pdb with ``--trace`` and parametrized tests by exiting pytest.
2+
3+
Using ``[q]uit`` when in pdb will now exit pytest, instead of continue to run
4+
the remaining tests.

src/_pytest/debugging.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ def do_continue(self, arg):
115115

116116
do_c = do_cont = do_continue
117117

118+
def set_quit(self):
119+
super(_PdbWrapper, self).set_quit()
120+
outcomes.exit("Quitting debugger")
121+
118122
def setup(self, f, tb):
119123
"""Suspend on setup().
120124
@@ -136,6 +140,7 @@ def setup(self, f, tb):
136140

137141
if set_break:
138142
_pdb.set_trace(frame)
143+
return _pdb
139144

140145

141146
class PdbInvoke(object):
@@ -161,9 +166,9 @@ def pytest_pyfunc_call(self, pyfuncitem):
161166

162167

163168
def _test_pytest_function(pyfuncitem):
164-
pytestPDB.set_trace(set_break=False)
169+
_pdb = pytestPDB.set_trace(set_break=False)
165170
testfunction = pyfuncitem.obj
166-
pyfuncitem.obj = pdb.runcall
171+
pyfuncitem.obj = _pdb.runcall
167172
if pyfuncitem._isyieldedfunction():
168173
arg_list = list(pyfuncitem._args)
169174
arg_list.insert(0, testfunction)
@@ -202,8 +207,7 @@ def _enter_pdb(node, excinfo, rep):
202207
tw.sep(">", "entering PDB")
203208
tb = _postmortem_traceback(excinfo)
204209
rep._pdbshown = True
205-
if post_mortem(tb):
206-
outcomes.exit("Quitting debugger")
210+
post_mortem(tb)
207211
return rep
208212

209213

@@ -234,4 +238,5 @@ def get_stack(self, f, t):
234238
p = Pdb()
235239
p.reset()
236240
p.interaction(None, t)
237-
return p.quitting
241+
if p.quitting:
242+
outcomes.exit("Quitting debugger")

testing/test_pdb.py

Lines changed: 35 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -147,29 +147,6 @@ def test_func():
147147
assert rep.failed
148148
assert len(pdblist) == 1
149149

150-
def test_pdb_interaction(self, testdir):
151-
p1 = testdir.makepyfile(
152-
"""
153-
def test_1():
154-
i = 0
155-
assert i == 1
156-
157-
def test_not_called_due_to_quit():
158-
pass
159-
"""
160-
)
161-
child = testdir.spawn_pytest("--pdb %s" % p1)
162-
child.expect(".*def test_1")
163-
child.expect(".*i = 0")
164-
child.expect("Pdb")
165-
child.sendeof()
166-
rest = child.read().decode("utf8")
167-
assert "= 1 failed in" in rest
168-
assert "def test_1" not in rest
169-
assert "Exit: Quitting debugger" in rest
170-
assert "PDB continue (IO-capturing resumed)" not in rest
171-
self.flush(child)
172-
173150
@staticmethod
174151
def flush(child):
175152
if platform.system() == "Darwin":
@@ -214,40 +191,32 @@ def test_one(self):
214191
child.sendeof()
215192
self.flush(child)
216193

217-
def test_pdb_print_captured_stdout(self, testdir):
194+
def test_pdb_print_captured_stdout_and_stderr(self, testdir):
218195
p1 = testdir.makepyfile(
219196
"""
220197
def test_1():
198+
import sys
199+
sys.stderr.write("get\\x20rekt")
221200
print("get\\x20rekt")
222201
assert False
202+
203+
def test_not_called_due_to_quit():
204+
pass
223205
"""
224206
)
225207
child = testdir.spawn_pytest("--pdb %s" % p1)
226208
child.expect("captured stdout")
227209
child.expect("get rekt")
228-
child.expect("Pdb")
229-
child.sendeof()
230-
rest = child.read().decode("utf8")
231-
assert "1 failed" in rest
232-
assert "get rekt" not in rest
233-
self.flush(child)
234-
235-
def test_pdb_print_captured_stderr(self, testdir):
236-
p1 = testdir.makepyfile(
237-
"""
238-
def test_1():
239-
import sys
240-
sys.stderr.write("get\\x20rekt")
241-
assert False
242-
"""
243-
)
244-
child = testdir.spawn_pytest("--pdb %s" % p1)
245210
child.expect("captured stderr")
246211
child.expect("get rekt")
212+
child.expect("traceback")
213+
child.expect("def test_1")
247214
child.expect("Pdb")
248215
child.sendeof()
249216
rest = child.read().decode("utf8")
250-
assert "1 failed" in rest
217+
assert "Exit: Quitting debugger" in rest
218+
assert "= 1 failed in" in rest
219+
assert "def test_1" not in rest
251220
assert "get rekt" not in rest
252221
self.flush(child)
253222

@@ -375,15 +344,17 @@ def test_1():
375344
i = 0
376345
print("hello17")
377346
pytest.set_trace()
378-
x = 3
347+
i == 1
348+
assert 0
379349
"""
380350
)
381351
child = testdir.spawn_pytest(str(p1))
382-
child.expect("test_1")
383-
child.expect("x = 3")
352+
child.expect(r"test_1\(\)")
353+
child.expect("i == 1")
384354
child.expect("Pdb")
385-
child.sendeof()
355+
child.sendline("c")
386356
rest = child.read().decode("utf-8")
357+
assert "AssertionError" in rest
387358
assert "1 failed" in rest
388359
assert "def test_1" in rest
389360
assert "hello17" in rest # out is captured
@@ -402,9 +373,9 @@ def test_1():
402373
child.expect("Pdb")
403374
child.sendeof()
404375
rest = child.read().decode("utf8")
405-
assert "1 failed" in rest
376+
assert "no tests ran" in rest
406377
assert "reading from stdin while output" not in rest
407-
assert "BdbQuit" in rest
378+
assert "BdbQuit" not in rest
408379
self.flush(child)
409380

410381
def test_pdb_and_capsys(self, testdir):
@@ -496,6 +467,7 @@ def test_1():
496467
print("hello18")
497468
pytest.set_trace()
498469
x = 4
470+
assert 0
499471
"""
500472
)
501473
child = testdir.spawn_pytest(str(p1))
@@ -508,11 +480,11 @@ def test_1():
508480
child.expect(r"PDB set_trace \(IO-capturing turned off\)")
509481
child.expect("x = 4")
510482
child.expect("Pdb")
511-
child.sendeof()
483+
child.sendline("c")
512484
child.expect("_ test_1 _")
513485
child.expect("def test_1")
514-
child.expect("Captured stdout call")
515486
rest = child.read().decode("utf8")
487+
assert "Captured stdout call" in rest
516488
assert "hello17" in rest # out is captured
517489
assert "hello18" in rest # out is captured
518490
assert "1 failed" in rest
@@ -797,15 +769,26 @@ def test_trace_sets_breakpoint(self, testdir):
797769
"""
798770
def test_1():
799771
assert True
772+
773+
def test_2():
774+
pass
775+
776+
def test_3():
777+
pass
800778
"""
801779
)
802780
child = testdir.spawn_pytest("--trace " + str(p1))
803781
child.expect("test_1")
804782
child.expect("Pdb")
805-
child.sendeof()
783+
child.sendline("c")
784+
child.expect("test_2")
785+
child.expect("Pdb")
786+
child.sendline("q")
787+
child.expect_exact("Exit: Quitting debugger")
806788
rest = child.read().decode("utf8")
807-
assert "1 passed" in rest
789+
assert "1 passed in" in rest
808790
assert "reading from stdin while output" not in rest
791+
assert "Exit: Quitting debugger" in child.before.decode("utf8")
809792
TestPDB.flush(child)
810793

811794

0 commit comments

Comments
 (0)