Commit 44f2b640 authored by Georg Brandl's avatar Georg Brandl

#7245: Add a SIGINT handler on continue in pdb that allows to break a program...

#7245: Add a SIGINT handler on continue in pdb that allows to break a program again by pressing Ctrl-C.
parent 1ed77f30
......@@ -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)
......
......@@ -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
......
......@@ -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
......
......@@ -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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment