homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: better Ctrl-C support in pdb (program can be resumed) (issue216067)
Type: behavior Stage:
Components: Library (Lib) Versions: Python 3.2
process
Status: closed Resolution: accepted
Dependencies: Superseder:
Assigned To: gregory.p.smith Nosy List: draghuram, georg.brandl, gregory.p.smith, isandler, r.david.murray
Priority: normal Keywords: patch

Created on 2009年10月31日 19:37 by isandler, last changed 2022年04月11日 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
sig.patch.v0 isandler, 2009年10月31日 19:37
sig.patch.v1 isandler, 2010年02月22日 02:19
sig.patch.v2 isandler, 2010年02月27日 04:11
sig.patch.v3.diff isandler, 2010年03月06日 19:20 review
test_pdb2.py isandler, 2010年03月22日 05:56
pdb-keyboardinterrupt.diff georg.brandl, 2010年07月30日 22:30 review
Messages (23)
msg94764 - (view) Author: Ilya Sandler (isandler) Date: 2009年10月31日 19:37
Currently, pressing Ctrl-C in pdb will terminate the program and throw
the user into post-mortem debugging.
Other debuggers (e.g gdb and pydb) treat Ctrl-C differently: Ctrl-C only
stops the program and the user can resume it if needed. 
I believe current pdb behavior is user-unfriendly (as wanting to stop
and then resume the execution is a very common use case which is not
supported by pdb at all (I think)).
The attached patch changes pdb's Ctrl-C behavior to match
gdb's: Ctrl-C will stop the program and the user can resume the
execution later.
msg94782 - (view) Author: Raghuram Devarakonda (draghuram) (Python triager) Date: 2009年11月01日 04:45
It is better for this functionality to be added in "Cmd" module as that
will benefit all users of that module. Please see bug #1294 which has a
patch for this purpose. It would be nice if you can test with that patch
and see if pdb works as you expected.
msg94811 - (view) Author: Ilya Sandler (isandler) Date: 2009年11月01日 22:44
No,I don't think patch in the issue #1294 addresses the problem which
I'm trying to solve.
I tried applying patch#1294, and Ctrl-C will still throws your debugger
into postmortem mode and I don't think you can change that by overriding
do_KeyboardInterrupt(): when do_KbdInterrupt() is called you cannot
resume execution (or at least I don't know any way of doing it).
My patch handles the SIGINT directly which allows it to set tracing and
resume the program immediately (and keyboardinterrupt is never raised)
I'll also add comments to patch#1294
msg99661 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2010年02月21日 14:07
http://codereview.appspot.com/216067/show 
msg99702 - (view) Author: Ilya Sandler (isandler) Date: 2010年02月22日 02:19
I fixed some of the style issues mentioned on appspot. (I was not sure about some of them and responded to them in appspot comments).
Also sigHandler became sighandler for consistency with the rest of pdb.py. 
The new version of the patch is attached.
However, it appears that I've been a bit over-optimistic about the lack of side-effects. In particular, the patch results in an very ugly error message when Ctrl-C is pressed while at pdb prompt..
*** AttributeError: AttributeError("'NoneType' object has no attribute 'f_globals'",)
Everything still seems to be working, but it's definitely ugly (and behaves differently on Windows and Linux).
I will try to summarize possible Ctrl-C scenarios in a separate post
msg99706 - (view) Author: Ilya Sandler (isandler) Date: 2010年02月22日 03:00
Here is a list of Ctrl-C scenarios: ("current" below means the prepatch version of pdb).
1. program is running (last command was "c", "n", etc). Currently, Ctrl-C throws debugger into postmortem. Desired behavior: interrupt the program. This is the only scenario supported by the patch.
2. Program is stopped (debugger is interacting with the user). Currently, Ctrl-C will throw debugger into postmortem. Desired behaviour: either ignore Ctrl-C or abandon the current command (that's what gdb does).
3. Program is stopped and pdb runs one of the commands which catch exceptions (e.g "p"). Currently, Ctrl-C will abort the command and return pdb to the prompt. I think this behavior should be kept.
4. Program finished (debugger is in postmortem). Currently, Ctrl-C will quit the debugger. Desired behavior: either ignore Ctrl-C or abandon the current command.
Essentially, I think the best behavior is to have Ctrl-C to interrupt whatever pdb is doing and return to the fresh prompt.
I am assuming that behavior on Windows and Linux should be identical/nearly identical.
Does the above list make sense?
I would greatly appreciate any feedback/comments/guidance/etc.
msg99708 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2010年02月22日 03:28
Your summary makes sense to me, at least.
msg100177 - (view) Author: Ilya Sandler (isandler) Date: 2010年02月27日 04:11
Another iteration of the patch. Now sigint_handler will generate 
KeyboardInterrupts when pdb is in the commandloop
I think this guarantees consistent "Ctrl-C interrupts the current pdb action" behavior and the program is still resumable.
The "commands" command required a bit of special handling to unroll the changes if KbdInt happens.
The patch was tested on Linux and Vista.
msg100220 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2010年02月28日 20:14
I put your sig.patch.v2 in http://codereview.appspot.com/216067/show and added some comments there. (and attempted to have it CC the tracker so they show up here but its been a while since i've done that, not sure how to make that work)
msg100221 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2010年02月28日 20:23
Reviewers: gregory.p.smith, Benjamin, ilya.sandler,
Message:
Also, can you take a look at how the pdb unittests work and see if you
can come up with a way to unittest the KeyboardInterrupt behavior?
Particular for the 4 scenarios you outlined in your prior comments in
the bug (those all make sense to me).
http://codereview.appspot.com/216067/diff/2001/2002
File Lib/pdb.py (right):
http://codereview.appspot.com/216067/diff/2001/2002#newcode63
Lib/pdb.py:63: def sigint_handler(self, signum, frame):
Please move this below the __init__ definition. It makes classes odd to
read when __init__ isn't the first method defined when people are
looking for the constructor to see how to use it.
http://codereview.appspot.com/216067/diff/2001/2002#newcode64
Lib/pdb.py:64: if self.allow_kbdint:
Initialize self.allow_kdbint in __init__ so that a SIGINT coming in
before _cmdloop has run doesn't cause an AttributeError.
http://codereview.appspot.com/216067/diff/2001/2002#newcode215
Lib/pdb.py:215: # keyboard interrupts allow for an easy way to interrupt
"to cancel the current command"
http://codereview.appspot.com/216067/diff/2001/2002#newcode356
Lib/pdb.py:356: #it appears that that when pdb is reading input from a
pipe
Space after the # please.
Also, could you add a comment in here describing what the effect of this
code is?
It looks like you catch KeyboardInterrupt here and remove the particular
interrupted command from the list of commands to run at the current
breakpoint but I may be misreading things as I haven't spent much time
in pdb.py.
Please review this at http://codereview.appspot.com/216067/show
Affected files:
 M Lib/pdb.py
Index: Lib/pdb.py
===================================================================
--- Lib/pdb.py	(revision 78520)
+++ Lib/pdb.py	(working copy)
@@ -13,8 +13,10 @@
 import re
 import pprint
 import traceback
+import signal
+
 class Restart(Exception):
 """Causes a debugger to be restarted for the debugged python 
program."""
 pass
@@ -58,6 +60,13 @@
 class Pdb(bdb.Bdb, cmd.Cmd):
+ def sigint_handler(self, signum, frame):
+ if self.allow_kbdint:
+ raise KeyboardInterrupt()
+ print >>self.stdout, "\nProgram interrupted. (Use 'cont' to 
resume)."
+ self.set_step()
+ self.set_trace(frame)
+
 def __init__(self, completekey='tab', stdin=None, stdout=None, 
skip=None):
 bdb.Bdb.__init__(self, skip=skip)
 cmd.Cmd.__init__(self, completekey, stdin, stdout)
@@ -72,6 +81,7 @@
 import readline
 except ImportError:
 pass
+ signal.signal(signal.SIGINT, self.sigint_handler)
 # Read $HOME/.pdbrc and ./.pdbrc
 self.rcLines = []
@@ -176,7 +186,7 @@
 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
@@ -199,11 +209,22 @@
 self.interaction(frame, exc_traceback)
 # General interaction function
+ def _cmdloop(self):
+ while 1:
+ try:
+ # keyboard interrupts allow for an easy way to interrupt
+ # cancel current command
+ self.allow_kbdint = True
+ self.cmdloop()
+ self.allow_kbdint = False
+ break
+ except KeyboardInterrupt:
+ print >>self.stdout, '--KeyboardInterrupt--'
 def interaction(self, frame, traceback):
 self.setup(frame, traceback)
 self.print_stack_entry(self.stack[self.curindex])
- self.cmdloop()
+ self._cmdloop()
 self.forget()
 def displayhook(self, obj):
@@ -329,9 +350,18 @@
 prompt_back = self.prompt
 self.prompt = '(com) '
 self.commands_defining = True
- self.cmdloop()
- self.commands_defining = False
- self.prompt = prompt_back
+ try:
+ self.cmdloop()
+ except (KeyboardInterrupt, IOError):
+ #it appears that that when pdb is reading input from a pipe
+ # we may get IOErrors, rather than KeyboardInterrupt
+ self.commands.pop(bnum) # remove this cmd list
+ self.commands_doprompt.pop(bnum)
+ self.commands_silent.pop(bnum)
+ raise KeyboardInterrupt()
+ finally:
+ self.commands_defining = False
+ self.prompt = prompt_back
 def do_break(self, arg, temporary = 0):
 # break [ ([filename:]lineno | function) [, "condition"] ]
msg100542 - (view) Author: Ilya Sandler (isandler) Date: 2010年03月06日 19:20
Another version of the patch is attached ( I think, I fixed all the remaining style issues).
I'll answer the testing question in a separate post
msg100543 - (view) Author: Ilya Sandler (isandler) Date: 2010年03月06日 19:27
new version of the patch is uploaded to bugs.python.org
http://codereview.appspot.com/216067/diff/2001/2002
File Lib/pdb.py (right):
http://codereview.appspot.com/216067/diff/2001/2002#newcode63
Lib/pdb.py:63: def sigint_handler(self, signum, frame):
On 2010年02月28日 20:12:00, gregory.p.smith wrote:
> Please move this below the __init__ definition. It makes classes odd
to read
> when __init__ isn't the first method defined when people are looking
for the
> constructor to see how to use it.
Done.
http://codereview.appspot.com/216067/diff/2001/2002#newcode64
Lib/pdb.py:64: if self.allow_kbdint:
On 2010年02月28日 20:12:00, gregory.p.smith wrote:
> Initialize self.allow_kdbint in __init__ so that a SIGINT coming in
before
> _cmdloop has run doesn't cause an AttributeError.
Done.
http://codereview.appspot.com/216067/diff/2001/2002#newcode215
Lib/pdb.py:215: # keyboard interrupts allow for an easy way to interrupt
On 2010年02月28日 20:12:00, gregory.p.smith wrote:
> "to cancel the current command"
I changed the wording a bit, should be ok now.
http://codereview.appspot.com/216067/diff/2001/2002#newcode356
Lib/pdb.py:356: #it appears that that when pdb is reading input from a
pipe
On 2010年02月28日 20:12:00, gregory.p.smith wrote:
> Space after the # please.
this code
> is?
particular
> interrupted command from the list of commands to run at the current
breakpoint
> but I may be misreading things as I haven't spent much time in pdb.py.
Done. I've also added a comment to explain what's going on.
http://codereview.appspot.com/216067/show 
msg100555 - (view) Author: Ilya Sandler (isandler) Date: 2010年03月07日 00:10
> Also, can you take a look at how the pdb unittests work and see if you
can come up with a way to unittest the KeyboardInterrupt behavior?
Yes, this is doable. In fact, I already have such tests written (unix only though). The tests are assert based but it should not be difficult to convert them to unittest. Moreover, I have many more tests for pdb written in the same style. 
However, these tests are not easily (and possibly not at all) integratable with existing test_pdb.py module. (See below for the problems). So would it be acceptable to have these tests as a separate module (test_pdb2.py or some such)? (I might also need some help with integrating the module)
Background
----------
Here is the basic problem: testing/debugging a debugger is hard by itself (you need to deal with 2 programs at once: the one being debugged and the debugger which run intermittently), now throw in doctest and it becomes much harder (as everything you do now gets covered by another layer). And now we need to test signals and some of the tests will likely be platform specific which makes it even worse. 
In contrast, in my tests the snippets of code are written into a tmp file and then are fed into debugger, the debugger itself is run as a subprocess. So if a test fails, it can be easily rerun under debugger manually and you can test for things like pdb exits and stalls.
Here is a snippet from my pdb tests (just to give an idea how they would look like: essentially, send a command to pdb, check the response).
 pdb=PdbTester("pdb_t_hello","""\
 import time
 for i in xrange(100000000):
 time.sleep(0.05)
 """)
 pdb.pdbHandle.stdin.write("c\n")
 time.sleep(0.01)
 #pdb_t_hello running, try to interrupt it
 pdb.pdbHandle.send_signal(signal.SIGINT)
 pdb.waitForPrompt()
 pdb.queryAndMatch("p i", "0")
 pdb.query("n")
 pdb.query("n")
 pdb.queryAndMatch("p i", "1")
 pdb.query("s")
 pdb.query("s")
 pdb.queryAndMatch("p i","2")
 pdb.pdbHandle.stdin.write("c\n")
 time.sleep(0.03)
 pdb.pdbHandle.send_signal(signal.SIGINT)
 pdb.waitForPrompt()
 pdb.queryAndMatch("p i","3")
msg101482 - (view) Author: Ilya Sandler (isandler) Date: 2010年03月22日 05:56
I'm attaching a test for Ctrl-C behavior on Linux (the patch itself works on Windows too, but I am not sure how to send Ctrl-C on windows programatically and subprocess does not have this functionality either).
The test_pdb2.py module is generic and can be extended to test other functionality. But, as discussed earlier, it cannot be easily (if at all) integrated into existing test_pdb.py.
Note that the test module will NOT work with existing pdb (as it doesnot have expected Ctrl-C) behavior, but on can specify alternative pdb location from command line:
 env DEBUG_PDB=./pdb.py ./test_pdb2.py
msg101971 - (view) Author: Ilya Sandler (isandler) Date: 2010年03月31日 02:27
Is there anything else I can do for this patch?
msg104739 - (view) Author: Ilya Sandler (isandler) Date: 2010年05月01日 19:10
a note on testing: it should be possible to integrate the tests into existing test_pdb.py by simply placing subprocess based tests next to doctest-based tests. This way pdb tests will at least be in a single module. (this is an approach taken by a patch in 
http://bugs.python.org/issue7964)
Would it be better?
msg105348 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2010年05月08日 23:39
Committed to trunk in r81012. though as this missed 2.7beta2 its possible that will be rejected and this becomes a 3.x only feature.
I'm porting to py3k now.
msg105360 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2010年05月09日 01:21
And reverted in trunk r81013. Multiple buildbot problems from the initial commit due to the unittest.
This is likely to be py3k only at this point.
I do believe sig.patch.v3 is fine, but its the test_pdb2 unittest that is difficult to make work well.
msg106031 - (view) Author: Ilya Sandler (isandler) Date: 2010年05月19日 03:48
I tried to understand the cause of failures and I don't see how test_pdb2 could have caused them ;-).
Here is the relevant part of buildbot timeline:
http://www.python.org/dev/buildbot/trunk/?last_time=1273368351&show_time=7400
The only test failures which have log files were sparc solaris 10 and ia64 and both failures were in test_unittest. All other buildbot failures don't have test logs associated with them..
Is there a way to access test logs for other platforms?
msg112107 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2010年07月30日 22:21
I committed the "commands" part of the patch in r83308.
For the SIGINT part, I'm concerned that the SIGINT handler is set
in the Pdb constructor, since it's a processwide setting I think it
should a) be set only before sys.settrace() and b) be restored appropriately when debugging is finished.
msg112108 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2010年07月30日 22:30
Adding the rest of the patch adapted for py3k trunk as of today.
msg122757 - (view) Author: Ilya Sandler (isandler) Date: 2010年11月29日 01:48
The patch tries to write to stdout in signal handler. 
This currently does not work in the python 3.x (see
http://bugs.python.org/issue10478).
msg123368 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2010年12月04日 16:15
Committed rest of patch in r87045. Will try to get test_pdb2 in shape and working on all platforms.
History
Date User Action Args
2022年04月11日 14:56:54adminsetgithub: 51494
2010年12月04日 16:15:23georg.brandlsetstatus: open -> closed
resolution: accepted
messages: + msg123368
2010年11月29日 01:48:57isandlersetmessages: + msg122757
2010年07月30日 22:30:11georg.brandlsetfiles: + pdb-keyboardinterrupt.diff
keywords: + patch
messages: + msg112108
2010年07月30日 22:21:43georg.brandlsetnosy: + georg.brandl
messages: + msg112107
2010年05月19日 03:48:25isandlersetmessages: + msg106031
2010年05月09日 01:21:43gregory.p.smithsetmessages: + msg105360
versions: - Python 2.7
2010年05月08日 23:39:38gregory.p.smithsetmessages: + msg105348
versions: + Python 3.2
2010年05月01日 19:10:42isandlersetmessages: + msg104739
2010年03月31日 02:27:14isandlersetmessages: + msg101971
2010年03月22日 05:56:26isandlersetfiles: + test_pdb2.py

messages: + msg101482
2010年03月07日 00:10:47isandlersetmessages: + msg100555
2010年03月06日 19:27:43isandlersetmessages: + msg100543
2010年03月06日 19:20:32isandlersetfiles: + sig.patch.v3.diff

messages: + msg100542
2010年02月28日 20:23:29gregory.p.smithsetmessages: + msg100221
title: better Ctrl-C support in pdb (program can be resumed) -> better Ctrl-C support in pdb (program can be resumed) (issue216067)
2010年02月28日 20:14:12gregory.p.smithsetmessages: + msg100220
2010年02月27日 04:11:09isandlersetfiles: + sig.patch.v2

messages: + msg100177
2010年02月22日 03:28:21r.david.murraysetnosy: + r.david.murray
messages: + msg99708
2010年02月22日 03:00:51isandlersetmessages: + msg99706
2010年02月22日 02:19:38isandlersetfiles: + sig.patch.v1

messages: + msg99702
2010年02月21日 14:07:40gregory.p.smithsetpriority: normal

nosy: + gregory.p.smith
messages: + msg99661

assignee: gregory.p.smith
2009年11月01日 22:44:20isandlersetmessages: + msg94811
2009年11月01日 04:45:47draghuramsetnosy: + draghuram
messages: + msg94782
2009年10月31日 19:37:55isandlercreate

AltStyle によって変換されたページ (->オリジナル) /