Skip to content

Commit 648e993

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 233c2a2 commit 648e993

File tree

3 files changed

+50
-58
lines changed

3 files changed

+50
-58
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`` by exiting pytest.
2+
3+
Pressing q when in pdb will now exit pytest, instead of continue to run the
4+
remaining tests.

src/_pytest/debugging.py

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

102102
do_c = do_cont = do_continue
103103

104+
def set_quit(self):
105+
super(_PdbWrapper, self).set_quit()
106+
outcomes.exit("Quitting debugger")
107+
104108
def setup(self, f, tb):
105109
"""Suspend on setup().
106110
@@ -122,6 +126,7 @@ def setup(self, f, tb):
122126

123127
if set_break:
124128
_pdb.set_trace(frame)
129+
return _pdb
125130

126131

127132
class PdbInvoke(object):
@@ -147,9 +152,9 @@ def pytest_pyfunc_call(self, pyfuncitem):
147152

148153

149154
def _test_pytest_function(pyfuncitem):
150-
pytestPDB.set_trace(set_break=False)
155+
_pdb = pytestPDB.set_trace(set_break=False)
151156
testfunction = pyfuncitem.obj
152-
pyfuncitem.obj = pdb.runcall
157+
pyfuncitem.obj = _pdb.runcall
153158
if pyfuncitem._isyieldedfunction():
154159
arg_list = list(pyfuncitem._args)
155160
arg_list.insert(0, testfunction)
@@ -188,8 +193,7 @@ def _enter_pdb(node, excinfo, rep):
188193
tw.sep(">", "entering PDB")
189194
tb = _postmortem_traceback(excinfo)
190195
rep._pdbshown = True
191-
if post_mortem(tb):
192-
outcomes.exit("Quitting debugger")
196+
post_mortem(tb)
193197
return rep
194198

195199

@@ -220,4 +224,5 @@ def get_stack(self, f, t):
220224
p = Pdb()
221225
p.reset()
222226
p.interaction(None, t)
223-
return p.quitting
227+
if p.quitting:
228+
outcomes.exit("Quitting debugger")

testing/test_pdb.py

Lines changed: 36 additions & 53 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
@@ -781,15 +753,26 @@ def test_trace_sets_breakpoint(self, testdir):
781753
"""
782754
def test_1():
783755
assert True
756+
757+
def test_2():
758+
pass
759+
760+
def test_3():
761+
pass
784762
"""
785763
)
786764
child = testdir.spawn_pytest("--trace " + str(p1))
787765
child.expect("test_1")
788766
child.expect("Pdb")
789-
child.sendeof()
767+
child.sendline("c")
768+
child.expect("test_2")
769+
child.expect("Pdb")
770+
child.sendline("q")
771+
child.expect_exact("Exit: Quitting debugger")
790772
rest = child.read().decode("utf8")
791-
assert "1 passed" in rest
773+
assert "1 passed in" in rest
792774
assert "reading from stdin while output" not in rest
775+
assert "Exit: Quitting debugger" in child.before.decode("utf8")
793776
TestPDB.flush(child)
794777

795778
def test_trace_against_yield_test(self, testdir):
@@ -805,7 +788,7 @@ def test_1():
805788
child = testdir.spawn_pytest("--trace " + str(p1))
806789
child.expect("is_equal")
807790
child.expect("Pdb")
808-
child.sendeof()
791+
child.sendline("c")
809792
rest = child.read().decode("utf8")
810793
assert "1 passed" in rest
811794
assert "reading from stdin while output" not in rest

0 commit comments

Comments
 (0)