Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 44f2b64

Browse files
committed
#7245: Add a SIGINT handler on continue in pdb that allows to break a program again by pressing Ctrl-C.
1 parent 1ed77f3 commit 44f2b64

4 files changed

Lines changed: 47 additions & 7 deletions

File tree

Doc/library/pdb.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ The ``run_*`` functions and :func:`set_trace` are aliases for instantiating the
135135
:class:`Pdb` class and calling the method of the same name. If you want to
136136
access further features, you have to do this yourself:
137137

138-
.. class:: Pdb(completekey='tab', stdin=None, stdout=None, skip=None)
138+
.. class:: Pdb(completekey='tab', stdin=None, stdout=None, skip=None, \
139+
nosigint=False)
139140

140141
:class:`Pdb` is the debugger class.
141142

@@ -146,13 +147,22 @@ access further features, you have to do this yourself:
146147
patterns. The debugger will not step into frames that originate in a module
147148
that matches one of these patterns. [1]_
148149

150+
By default, Pdb sets a handler for the SIGINT signal (which is sent when the
151+
user presses Ctrl-C on the console) when you give a ``continue`` command.
152+
This allows you to break into the debugger again by pressing Ctrl-C. If you
153+
want Pdb not to touch the SIGINT handler, set *nosigint* tot true.
154+
149155
Example call to enable tracing with *skip*::
150156

151157
import pdb; pdb.Pdb(skip=['django.*']).set_trace()
152158

153159
.. versionadded:: 3.1
154160
The *skip* argument.
155161

162+
.. versionadded:: 3.2
163+
The *nosigint* argument. Previously, a SIGINT handler was never set by
164+
Pdb.
165+
156166
.. method:: run(statement, globals=None, locals=None)
157167
runeval(expression, globals=None, locals=None)
158168
runcall(function, *args, **kwds)

Lib/bdb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def set_trace(self, frame=None):
214214
def set_continue(self):
215215
# Don't stop except at breakpoints or when finished
216216
self._set_stopinfo(self.botframe, None, -1)
217-
if not self.breaks:
217+
if not self.breaks and not self.watching:
218218
# no breakpoints; run without debugger overhead
219219
sys.settrace(None)
220220
frame = sys._getframe().f_back

Lib/pdb.py

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,15 @@
6666
# NOTE: the actual command documentation is collected from docstrings of the
6767
# commands and is appended to __doc__ after the class has been defined.
6868

69+
import os
70+
import re
6971
import sys
7072
import cmd
7173
import bdb
7274
import dis
73-
import os
74-
import re
7575
import code
7676
import pprint
77+
import signal
7778
import inspect
7879
import traceback
7980
import linecache
@@ -133,7 +134,8 @@ def lasti2lineno(code, lasti):
133134

134135
class Pdb(bdb.Bdb, cmd.Cmd):
135136

136-
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None):
137+
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
138+
nosigint=False):
137139
bdb.Bdb.__init__(self, skip=skip)
138140
cmd.Cmd.__init__(self, completekey, stdin, stdout)
139141
if stdout:
@@ -148,6 +150,8 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None):
148150
import readline
149151
except ImportError:
150152
pass
153+
self.allow_kbdint = False
154+
self.nosigint = nosigint
151155

152156
# Read $HOME/.pdbrc and ./.pdbrc
153157
self.rcLines = []
@@ -174,6 +178,15 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None):
174178
self.commands_bnum = None # The breakpoint number for which we are
175179
# defining a list
176180

181+
def sigint_handler(self, signum, frame):
182+
if self.allow_kbdint:
183+
raise KeyboardInterrupt
184+
self.message("\nProgram interrupted. (Use 'cont' to resume).")
185+
self.set_step()
186+
self.set_trace(frame)
187+
# restore previous signal handler
188+
signal.signal(signal.SIGINT, self._previous_sigint_handler)
189+
177190
def reset(self):
178191
bdb.Bdb.reset(self)
179192
self.forget()
@@ -261,7 +274,7 @@ def bp_commands(self, frame):
261274
if not self.commands_silent[currentbp]:
262275
self.print_stack_entry(self.stack[self.curindex])
263276
if self.commands_doprompt[currentbp]:
264-
self.cmdloop()
277+
self._cmdloop()
265278
self.forget()
266279
return
267280
return 1
@@ -286,6 +299,17 @@ def user_exception(self, frame, exc_info):
286299
self.interaction(frame, exc_traceback)
287300

288301
# General interaction function
302+
def _cmdloop(self):
303+
while True:
304+
try:
305+
# keyboard interrupts allow for an easy way to cancel
306+
# the current command, so allow them during interactive input
307+
self.allow_kbdint = True
308+
self.cmdloop()
309+
self.allow_kbdint = False
310+
break
311+
except KeyboardInterrupt:
312+
self.message('--KeyboardInterrupt--')
289313

290314
def interaction(self, frame, traceback):
291315
if self.setup(frame, traceback):
@@ -294,7 +318,7 @@ def interaction(self, frame, traceback):
294318
self.forget()
295319
return
296320
self.print_stack_entry(self.stack[self.curindex])
297-
self.cmdloop()
321+
self._cmdloop()
298322
self.forget()
299323

300324
def displayhook(self, obj):
@@ -909,6 +933,9 @@ def do_continue(self, arg):
909933
"""c(ont(inue))
910934
Continue execution, only stop when a breakpoint is encountered.
911935
"""
936+
if not self.nosigint:
937+
self._previous_sigint_handler = \
938+
signal.signal(signal.SIGINT, self.sigint_handler)
912939
self.set_continue()
913940
return 1
914941
do_c = do_cont = do_continue

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Core and Builtins
4949
Library
5050
-------
5151

52+
- Issue #7245: Add a SIGINT handler in pdb that allows to break a program
53+
again after a "continue" command.
54+
5255
- Add the "interact" pdb command.
5356

5457
- Issue #7905: Actually respect the keyencoding parameter to shelve.Shelf.

0 commit comments

Comments
 (0)