##// END OF EJS Templates
Backport PR #12168: Make IPython.core.debugger interruptible by KeyboardInterrupt
Matthias Bussonnier -
Show More
@@ -0,0 +1,4 b''
1 IPython.core.debugger.Pdb is now interruptible
2 ==============================================
3
4 A ``KeyboardInterrupt`` will now interrupt IPython's extended debugger, in order to make Jupyter able to interrupt it.
@@ -634,6 +634,34 b' class Pdb(OldPdb):'
634 634 do_w = do_where
635 635
636 636
637 class InterruptiblePdb(Pdb):
638 """Version of debugger where KeyboardInterrupt exits the debugger altogether."""
639
640 def cmdloop(self):
641 """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
642 try:
643 return OldPdb.cmdloop(self)
644 except KeyboardInterrupt:
645 self.stop_here = lambda frame: False
646 self.do_quit("")
647 sys.settrace(None)
648 self.quitting = False
649 raise
650
651 def _cmdloop(self):
652 while True:
653 try:
654 # keyboard interrupts allow for an easy way to cancel
655 # the current command, so allow them during interactive input
656 self.allow_kbdint = True
657 self.cmdloop()
658 self.allow_kbdint = False
659 break
660 except KeyboardInterrupt:
661 self.message('--KeyboardInterrupt--')
662 raise
663
664
637 665 def set_trace(frame=None):
638 666 """
639 667 Start debugging from `frame`.
@@ -4,8 +4,16 b''
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 import signal
7 8 import sys
9 import time
8 10 import warnings
11 from tempfile import NamedTemporaryFile
12 from subprocess import check_output, CalledProcessError, PIPE
13 import subprocess
14 from unittest.mock import patch
15 import builtins
16 import bdb
9 17
10 18 import nose.tools as nt
11 19
@@ -223,3 +231,26 b' def can_exit():'
223 231
224 232 >>> sys.settrace(old_trace)
225 233 '''
234
235
236 def test_interruptible_core_debugger():
237 """The debugger can be interrupted.
238
239 The presumption is there is some mechanism that causes a KeyboardInterrupt
240 (this is implemented in ipykernel). We want to ensure the
241 KeyboardInterrupt cause debugging to cease.
242 """
243 def raising_input(msg="", called=[0]):
244 called[0] += 1
245 if called[0] == 1:
246 raise KeyboardInterrupt()
247 else:
248 raise AssertionError("input() should only be called once!")
249
250 with patch.object(builtins, "input", raising_input):
251 debugger.InterruptiblePdb().set_trace()
252 # The way this test will fail is by set_trace() never exiting,
253 # resulting in a timeout by the test runner. The alternative
254 # implementation would involve a subprocess, but that adds issues with
255 # interrupting subprocesses that are rather complex, so it's simpler
256 # just to do it this way.
General Comments 0
You need to be logged in to leave comments. Login now