summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorJohannes Gijsbers <jlg@dds.nl>2004-10-12 18:12:09 (GMT)
committerJohannes Gijsbers <jlg@dds.nl>2004-10-12 18:12:09 (GMT)
commit25b38c89690e79e8f3bc78245b73017eed07f42e (patch)
treede48e9ecd72172d957793ec76352118d707b8f98 /Lib
parent51ee66e611ca16e51bea158e09db663fe0cdff22 (diff)
downloadcpython-25b38c89690e79e8f3bc78245b73017eed07f42e.zip
cpython-25b38c89690e79e8f3bc78245b73017eed07f42e.tar.gz
cpython-25b38c89690e79e8f3bc78245b73017eed07f42e.tar.bz2
Improvements when running pdb as a script.
Bug fixes: * Use fresh copy of globals/locals so the script being debugged can't access the pdb namespace (e.g.: p line_prefix will no longer work). * Remove pdb.py's path from sys.path. Having it in there is normally not a problem, but it could prove irritating when messing with PYTHONPATH or invoking pdb via /usr/bin/pdf. * You can now set a breakpoint on the script being debugged, even if the script doesn't end with a '.py' extension. Also, setting breakpoints with absolute paths now works reliably. Enhancements: * Go directly to the first line of the script. * Enter post-mortem debugging if the script being debugged doesn't catch an exception. * Restart the script being debugged and preserve debugger state when the script being debugged exits. Cleanup: * Moved the __main__ method into a main() function. * Kill the (undocumented, not in __all__) mainmodule/mainpyfile globals, add a mainpyfile attribute to pdb. Thanks Ilya Sandler for the patch!
Diffstat (limited to 'Lib')
-rwxr-xr-xLib/pdb.py97
1 files changed, 81 insertions, 16 deletions
diff --git a/Lib/pdb.py b/Lib/pdb.py
index c7ec9c4..f07e155 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -12,7 +12,7 @@ from repr import Repr
import os
import re
import pprint
-
+import traceback
# Create a custom safe Repr instance and increase its maxstring.
# The default of 30 truncates error messages too easily.
_repr = Repr()
@@ -57,6 +57,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
cmd.Cmd.__init__(self)
self.prompt = '(Pdb) '
self.aliases = {}
+ self.mainpyfile = ''
+ self._wait_for_mainpyfile = 0
# Try to load readline if it exists
try:
import readline
@@ -117,12 +119,19 @@ class Pdb(bdb.Bdb, cmd.Cmd):
def user_call(self, frame, argument_list):
"""This method is called when there is the remote possibility
that we ever need to stop in this function."""
+ if self._wait_for_mainpyfile:
+ return
if self.stop_here(frame):
print '--Call--'
self.interaction(frame, None)
def user_line(self, frame):
"""This function is called when we stop or break at this line."""
+ if self._wait_for_mainpyfile:
+ if (self.mainpyfile != self.canonic(frame.f_code.co_filename)
+ or frame.f_lineno<= 0):
+ return
+ self._wait_for_mainpyfile = 0
self.interaction(frame, None)
def user_return(self, frame, return_value):
@@ -281,8 +290,8 @@ class Pdb(bdb.Bdb, cmd.Cmd):
def defaultFile(self):
"""Produce a reasonable default."""
filename = self.curframe.f_code.co_filename
- if filename == '<string>' and mainpyfile:
- filename = mainpyfile
+ if filename == '<string>' and self.mainpyfile:
+ filename = self.mainpyfile
return filename
do_b = do_break
@@ -525,13 +534,16 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self.lastcmd = p.lastcmd
def do_quit(self, arg):
+ self._user_requested_quit = 1
self.set_quit()
return 1
+
do_q = do_quit
do_exit = do_quit
def do_EOF(self, arg):
print
+ self._user_requested_quit = 1
self.set_quit()
return 1
@@ -928,7 +940,16 @@ Deletes the specified alias."""
help()
def lookupmodule(self, filename):
- """Helper function for break/clear parsing -- may be overridden."""
+ """Helper function for break/clear parsing -- may be overridden.
+
+ lookupmodule() translates (possibly incomplete) file or module name
+ into an absolute file name.
+ """
+ if os.path.isabs(filename) and os.path.exists(filename):
+ return filename
+ f = os.path.join(sys.path[0], filename)
+ if os.path.exists(f) and self.canonic(f) == self.mainpyfile:
+ return f
root, ext = os.path.splitext(filename)
if ext == '':
filename = filename + '.py'
@@ -942,6 +963,24 @@ Deletes the specified alias."""
return fullname
return None
+ def _runscript(self, filename):
+ # Start with fresh empty copy of globals and locals and tell the script
+ # that it's being run as __main__ to avoid scripts being able to access
+ # the pdb.py namespace.
+ globals_ = {"__name__" : "__main__"}
+ locals_ = globals_
+
+ # When bdb sets tracing, a number of call and line events happens
+ # BEFORE debugger even reaches user's code (and the exact sequence of
+ # events depends on python version). So we take special measures to
+ # avoid stopping before we reach the main script (see user_line and
+ # user_call for details).
+ self._wait_for_mainpyfile = 1
+ self.mainpyfile = self.canonic(filename)
+ self._user_requested_quit = 0
+ statement = 'execfile( "%s")' % filename
+ self.run(statement, globals=globals_, locals=locals_)
+
# Simplified interface
def run(statement, globals=None, locals=None):
@@ -992,23 +1031,49 @@ def help():
print 'Sorry, can\'t find the help file "pdb.doc"',
print 'along the Python search path'
-mainmodule = ''
-mainpyfile = ''
-
-# When invoked as main program, invoke the debugger on a script
-if __name__=='__main__':
+def main():
if not sys.argv[1:]:
print "usage: pdb.py scriptfile [arg] ..."
sys.exit(2)
- mainpyfile = filename = sys.argv[1] # Get script filename
- if not os.path.exists(filename):
- print 'Error:', repr(filename), 'does not exist'
+ mainpyfile = sys.argv[1] # Get script filename
+ if not os.path.exists(mainpyfile):
+ print 'Error:', mainpyfile, 'does not exist'
sys.exit(1)
- mainmodule = os.path.basename(filename)
+
del sys.argv[0] # Hide "pdb.py" from argument list
- # Insert script directory in front of module search path
- sys.path.insert(0, os.path.dirname(filename))
+ # Replace pdb's dir with script's dir in front of module search path.
+ sys.path[0] = os.path.dirname(mainpyfile)
- run('execfile(%r)' % (filename,))
+ # Note on saving/restoring sys.argv: it's a good idea when sys.argv was
+ # modified by the script being debugged. It's a bad idea when it was
+ # changed by the user from the command line. The best approach would be to
+ # have a "restart" command which would allow explicit specification of
+ # command line arguments.
+ pdb = Pdb()
+ while 1:
+ try:
+ pdb._runscript(mainpyfile)
+ if pdb._user_requested_quit:
+ break
+ print "The program finished and will be restarted"
+ except SystemExit:
+ # In most cases SystemExit does not warrant a post-mortem session.
+ print "The program exited via sys.exit(). Exit status: ",
+ print sys.exc_info()[1]
+ except:
+ traceback.print_exc()
+ print "Uncaught exception. Entering post mortem debugging"
+ print "Running 'cont' or 'step' will restart the program"
+ t = sys.exc_info()[2]
+ while t.tb_next is not None:
+ t = t.tb_next
+ pdb.interaction(t.tb_frame,t)
+ print "Post mortem debugger finished. The "+mainpyfile+" will be restarted"
+
+
+# When invoked as main program, invoke the debugger on a script
+if __name__=='__main__':
+ main()
+