Skip to content

Commit

Permalink
pdb: fix usage in child thread after main thread exited
Browse files Browse the repository at this point in the history
  • Loading branch information
blueyed committed May 11, 2019
1 parent ceca35b commit 1588067
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 9 deletions.
1 change: 1 addition & 0 deletions changelog/5228.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix ``pdb.set_trace`` wrapper when used in child threads after main thread exited.
11 changes: 2 additions & 9 deletions src/_pytest/debugging.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@ def pytest_configure(config):
if config.getvalue("usepdb"):
config.pluginmanager.register(PdbInvoke(), "pdbinvoke")

pytestPDB._saved.append(
(pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config, pytestPDB._pdb_cls)
)
pytestPDB._saved.append(pdb.set_trace)
pdb.set_trace = pytestPDB.set_trace
pytestPDB._pluginmanager = config.pluginmanager
pytestPDB._config = config
Expand All @@ -88,12 +86,7 @@ def pytest_configure(config):
# NOTE: not using pytest_unconfigure, since it might get called although
# pytest_configure was not (if another plugin raises UsageError).
def fin():
(
pdb.set_trace,
pytestPDB._pluginmanager,
pytestPDB._config,
pytestPDB._pdb_cls,
) = pytestPDB._saved.pop()
pdb.set_trace = pytestPDB._saved.pop()

config._cleanup.append(fin)

Expand Down
44 changes: 44 additions & 0 deletions testing/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1191,3 +1191,47 @@ def test(monkeypatch):
result = testdir.runpytest(str(p1))
result.stdout.fnmatch_lines(["E *BdbQuit", "*= 1 failed in*"])
assert result.ret == 1


def test_pdb_in_thread_after_exit(testdir):
"""Ensure that pdb.set_trace works after main thread exited already.
This tests both continuation after the main thread exited, and a new
set_trace afterwards.
"""
p1 = testdir.makepyfile(
"""
import threading
main_thread = threading.main_thread()
def test():
evt = threading.Event()
def target():
print("target_" + "start")
evt.set()
assert main_thread.is_alive()
__import__('pdb').set_trace()
assert not main_thread.is_alive()
__import__('pdb').set_trace()
print("target_" + "end")
thread = threading.Thread(target=target)
thread.start()
evt.wait()
"""
)
child = testdir.spawn_pytest(str(p1) + " -s")
child.expect("target_start")
child.expect("= 1 passed in") # main thread exited
child.expect(r"\(Pdb")
child.sendline("c")
child.expect(r"\(Pdb")
child.sendline("c")
child.expect("target_end")
child.wait()
rest = child.read().decode("utf8")
assert "Exception in thread" not in rest
assert child.exitstatus == 0

0 comments on commit 1588067

Please sign in to comment.