summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2010-12-04 16:00:47 (GMT)
committerGeorg Brandl <georg@python.org>2010-12-04 16:00:47 (GMT)
commit44f2b640ff0260f5e338e41ad3a2d13185396979 (patch)
treea448ea5dea9367826b6d7e325c1487395c704fe8
parent1ed77f300b713166b0508eacd183c32f1d7437b2 (diff)
downloadcpython-44f2b640ff0260f5e338e41ad3a2d13185396979.zip
cpython-44f2b640ff0260f5e338e41ad3a2d13185396979.tar.gz
cpython-44f2b640ff0260f5e338e41ad3a2d13185396979.tar.bz2
#7245: Add a SIGINT handler on continue in pdb that allows to break a program again by pressing Ctrl-C.
-rw-r--r--Doc/library/pdb.rst12
-rw-r--r--Lib/bdb.py2
-rwxr-xr-xLib/pdb.py37
-rw-r--r--Misc/NEWS3
4 files changed, 47 insertions, 7 deletions
diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst
index db21d1f..959fde1 100644
--- a/Doc/library/pdb.rst
+++ b/Doc/library/pdb.rst
@@ -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)
diff --git a/Lib/bdb.py b/Lib/bdb.py
index 9f5e7ae..08dce8f 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -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
diff --git a/Lib/pdb.py b/Lib/pdb.py
index d6a9a92..ac53eba 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -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
diff --git a/Misc/NEWS b/Misc/NEWS
index c5a525f..a741d6e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.