diff --git a/Lib/pdb.py b/Lib/pdb.py --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -192,10 +192,11 @@ if self.allow_kbdint: raise KeyboardInterrupt self.message("\nProgram interrupted. (Use 'cont' to resume).") - self.set_step() - self.set_trace(frame) # restore previous signal handler signal.signal(signal.SIGINT, self._previous_sigint_handler) + frame.f_trace = self.trace_dispatch + sys.settrace(self.trace_dispatch) + self.set_step() def reset(self): bdb.Bdb.reset(self) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3,14 +3,20 @@ import imp import pdb import sys +import signal import unittest import subprocess import textwrap +try: + import threading +except ImportError: + threading = None from test import support # This little helper class is essential for testing pdb under doctest. from test.test_doctest import _FakeInput +mswindows = (sys.platform == "win32") class PdbTestInput(object): """Context manager that makes testing Pdb in doctests easier.""" @@ -599,7 +605,7 @@ class PdbTestCase(unittest.TestCase): - def run_pdb(self, script, commands): + def run_pdb(self, script, commands, sigint=False): """Run 'script' lines with pdb and the pdb 'commands'.""" filename = 'main.py' with open(filename, 'w') as f: @@ -611,6 +617,14 @@ stdin=subprocess.PIPE, stderr=subprocess.STDOUT, ) as proc: + # Interrupt the spawned process. + if threading and sigint: + def kill(): + # Wait for the subprocess to be fully started before + # sending the signal. + import time; time.sleep(1) + proc.send_signal(signal.SIGINT) + threading.Thread(target=kill).start() stdout, stderr = proc.communicate(str.encode(commands)) stdout = stdout and bytes.decode(stdout) stderr = stderr and bytes.decode(stderr) @@ -667,6 +681,29 @@ any('main.py(5)foo()->None' in l for l in stdout.splitlines()), 'Fail to step into the caller after a return') + @unittest.skipIf(mswindows or not threading, "posix with threads test") + def test_issue_XXX(self): + script = """ + import time + def bar(): + i = 1 + while i: + time.sleep(.100) + + bar() + """ + commands = """ + break bar + continue + continue + !print('value of i: ', i) + quit + """ + stdout, stderr = self.run_pdb(script, commands, sigint=True) + self.assertTrue( + any('value of i: 1' in l for l in stdout.splitlines()), + 'Interrupted debugging session not stopped in user frame.') + def tearDown(self): support.unlink(support.TESTFN)