#7245: Add a SIGINT handler on continue in pdb that allows to break a program again by pressing Ctrl-C.

This commit is contained in:
Georg Brandl 2010-12-04 16:00:47 +00:00
parent 1ed77f300b
commit 44f2b640ff
4 changed files with 47 additions and 7 deletions

View File

@ -135,7 +135,8 @@ The ``run_*`` functions and :func:`set_trace` are aliases for instantiating the
:class:`Pdb` class and calling the method of the same name. If you want to
access further features, you have to do this yourself:
.. class:: Pdb(completekey='tab', stdin=None, stdout=None, skip=None)
.. class:: Pdb(completekey='tab', stdin=None, stdout=None, skip=None, \
nosigint=False)
:class:`Pdb` is the debugger class.
@ -146,6 +147,11 @@ access further features, you have to do this yourself:
patterns. The debugger will not step into frames that originate in a module
that matches one of these patterns. [1]_
By default, Pdb sets a handler for the SIGINT signal (which is sent when the
user presses Ctrl-C on the console) when you give a ``continue`` command.
This allows you to break into the debugger again by pressing Ctrl-C. If you
want Pdb not to touch the SIGINT handler, set *nosigint* tot true.
Example call to enable tracing with *skip*::
import pdb; pdb.Pdb(skip=['django.*']).set_trace()
@ -153,6 +159,10 @@ access further features, you have to do this yourself:
.. versionadded:: 3.1
The *skip* argument.
.. versionadded:: 3.2
The *nosigint* argument. Previously, a SIGINT handler was never set by
Pdb.
.. method:: run(statement, globals=None, locals=None)
runeval(expression, globals=None, locals=None)
runcall(function, *args, **kwds)

View File

@ -214,7 +214,7 @@ class Bdb:
def set_continue(self):
# Don't stop except at breakpoints or when finished
self._set_stopinfo(self.botframe, None, -1)
if not self.breaks:
if not self.breaks and not self.watching:
# no breakpoints; run without debugger overhead
sys.settrace(None)
frame = sys._getframe().f_back

View File

@ -66,14 +66,15 @@ Debugger commands
# NOTE: the actual command documentation is collected from docstrings of the
# commands and is appended to __doc__ after the class has been defined.
import os
import re
import sys
import cmd
import bdb
import dis
import os
import re
import code
import pprint
import signal
import inspect
import traceback
import linecache
@ -133,7 +134,8 @@ line_prefix = '\n-> ' # Probably a better default
class Pdb(bdb.Bdb, cmd.Cmd):
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None):
def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
nosigint=False):
bdb.Bdb.__init__(self, skip=skip)
cmd.Cmd.__init__(self, completekey, stdin, stdout)
if stdout:
@ -148,6 +150,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
import readline
except ImportError:
pass
self.allow_kbdint = False
self.nosigint = nosigint
# Read $HOME/.pdbrc and ./.pdbrc
self.rcLines = []
@ -174,6 +178,15 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self.commands_bnum = None # The breakpoint number for which we are
# defining a list
def sigint_handler(self, signum, frame):
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)
def reset(self):
bdb.Bdb.reset(self)
self.forget()
@ -261,7 +274,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
if not self.commands_silent[currentbp]:
self.print_stack_entry(self.stack[self.curindex])
if self.commands_doprompt[currentbp]:
self.cmdloop()
self._cmdloop()
self.forget()
return
return 1
@ -286,6 +299,17 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self.interaction(frame, exc_traceback)
# General interaction function
def _cmdloop(self):
while True:
try:
# keyboard interrupts allow for an easy way to cancel
# the current command, so allow them during interactive input
self.allow_kbdint = True
self.cmdloop()
self.allow_kbdint = False
break
except KeyboardInterrupt:
self.message('--KeyboardInterrupt--')
def interaction(self, frame, traceback):
if self.setup(frame, traceback):
@ -294,7 +318,7 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self.forget()
return
self.print_stack_entry(self.stack[self.curindex])
self.cmdloop()
self._cmdloop()
self.forget()
def displayhook(self, obj):
@ -909,6 +933,9 @@ class Pdb(bdb.Bdb, cmd.Cmd):
"""c(ont(inue))
Continue execution, only stop when a breakpoint is encountered.
"""
if not self.nosigint:
self._previous_sigint_handler = \
signal.signal(signal.SIGINT, self.sigint_handler)
self.set_continue()
return 1
do_c = do_cont = do_continue

View File

@ -49,6 +49,9 @@ Core and Builtins
Library
-------
- Issue #7245: Add a SIGINT handler in pdb that allows to break a program
again after a "continue" command.
- Add the "interact" pdb command.
- Issue #7905: Actually respect the keyencoding parameter to shelve.Shelf.