From 55f88a2581b73d5b38578a756ff90da32a7f01fa 2020-04-21 20:27:09 From: Itamar Turner-Trauring Date: 2020-04-21 20:27:09 Subject: [PATCH] A maybe better-working interruptible Pdb. Also make separate class so we don't impact existing usage behavior. --- diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 8502874..48b24f0 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -290,7 +290,7 @@ class Pdb(OldPdb): try: OldPdb.interaction(self, frame, traceback) except KeyboardInterrupt: - raise + self.stdout.write('\n' + self.shell.get_exception_only()) def new_do_up(self, arg): OldPdb.do_up(self, arg) @@ -627,8 +627,22 @@ class Pdb(OldPdb): do_w = do_where + +class InterruptiblePdb(Pdb): + """Version of debugger where KeyboardInterrupt exits the debugger altogether.""" + + def cmdloop(self): + """Wrap cmdloop() such that KeyboardInterrupt stops the debugger.""" + try: + return OldPdb.cmdloop(self) + except KeyboardInterrupt: + self.stop_here = lambda frame: False + self.do_quit("") + sys.settrace(None) + self.quitting = False + raise + def _cmdloop(self): - # Variant that doesn't catch KeyboardInterrupts. while True: try: # keyboard interrupts allow for an easy way to cancel @@ -638,6 +652,7 @@ class Pdb(OldPdb): self.allow_kbdint = False break except KeyboardInterrupt: + self.message('--KeyboardInterrupt--') raise diff --git a/IPython/core/tests/test_debugger.py b/IPython/core/tests/test_debugger.py index 4cf7743..6950680 100644 --- a/IPython/core/tests/test_debugger.py +++ b/IPython/core/tests/test_debugger.py @@ -13,6 +13,7 @@ from subprocess import check_output, CalledProcessError, PIPE import subprocess from unittest.mock import patch import builtins +import bdb import nose.tools as nt @@ -236,11 +237,15 @@ def test_interruptible_core_debugger(): (this is implemented in ipykernel). We want to ensure the KeyboardInterrupt cause debugging to cease. """ - def raising_input(msg=""): - raise KeyboardInterrupt() + def raising_input(msg="", called=[0]): + called[0] += 1 + if called[0] == 1: + raise KeyboardInterrupt() + else: + raise AssertionError("input() should only be called once!") with patch.object(builtins, "input", raising_input): - debugger.set_trace() + debugger.InterruptiblePdb().set_trace() # The way this test will fail is by set_trace() never exiting, # resulting in a timeout by the test runner. The alternative # implementation would involve a subprocess, but that adds issues with