summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1998-07-20 23:13:54 (GMT)
committerGuido van Rossum <guido@python.org>1998-07-20 23:13:54 (GMT)
commitb5699c7240e085cb20972f388aa8e21387c48275 (patch)
tree625fa156d8d5f44b4ccc0cb61a2dc7811c39c200
parentc612681b20f2ff8786067a3d8c6d041bc64d0db0 (diff)
downloadcpython-b5699c7240e085cb20972f388aa8e21387c48275.zip
cpython-b5699c7240e085cb20972f388aa8e21387c48275.tar.gz
cpython-b5699c7240e085cb20972f388aa8e21387c48275.tar.bz2
Added support for specifying a filename for a breakpoint, roughly
according to an idea by Harri Pasanen (but with different syntax). This affects the 'break' and 'clear' commands and their help functions. Also added a helper method lookupmodule(). Also: - Try to import readline (important when pdb is used from/as a script). - Get rid of reference to ancient __privileged__ magic variable. - Moved all import out of functions to the top. - When used as a script, check that the script file exists.
-rwxr-xr-xLib/pdb.py142
1 files changed, 102 insertions, 40 deletions
diff --git a/Lib/pdb.py b/Lib/pdb.py
index 80aa54b..2824f4c 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -10,6 +10,7 @@ import linecache
import cmd
import bdb
import repr
+import os
# Interaction prompt line will separate file and call info from code
@@ -25,6 +26,11 @@ class Pdb(bdb.Bdb, cmd.Cmd):
bdb.Bdb.__init__(self)
cmd.Cmd.__init__(self)
self.prompt = '(Pdb) '
+ # Try to load readline if it exists
+ try:
+ import readline
+ except ImportError:
+ pass
def reset(self):
bdb.Bdb.reset(self)
@@ -75,7 +81,6 @@ class Pdb(bdb.Bdb, cmd.Cmd):
if line[:1] == '!': line = line[1:]
locals = self.curframe.f_locals
globals = self.curframe.f_globals
- globals['__privileged__'] = 1
try:
code = compile(line + '\n', '<stdin>', 'single')
exec code in globals, locals
@@ -93,38 +98,66 @@ class Pdb(bdb.Bdb, cmd.Cmd):
do_h = cmd.Cmd.do_help
def do_break(self, arg):
+ # break [ ([filename:]lineno | function) [, "condition"] ]
if not arg:
print self.get_all_breaks() # XXX
return
- # Try line number as argument
- try:
- arg = eval(arg, self.curframe.f_globals,
- self.curframe.f_locals)
- except:
- print '*** Could not eval argument:', arg
- return
-
- # Check for condition
- try: arg, cond = arg
- except: arg, cond = arg, None
-
- try:
- lineno = int(arg)
- filename = self.curframe.f_code.co_filename
- except:
- # Try function name as the argument
+ # parse arguments; comma has lowest precendence
+ # and cannot occur in filename
+ filename = None
+ lineno = None
+ cond = None
+ comma = string.find(arg, ',')
+ if comma > 0:
+ # parse stuff after comma: "condition"
+ cond = string.lstrip(arg[comma+1:])
+ arg = string.rstrip(arg[:comma])
try:
- func = arg
- if hasattr(func, 'im_func'):
- func = func.im_func
- code = func.func_code
+ cond = eval(
+ cond,
+ self.curframe.f_globals,
+ self.curframe.f_locals)
except:
- print '*** The specified object',
- print 'is not a function', arg
+ print '*** Could not eval condition:', cond
return
- lineno = code.co_firstlineno
- filename = code.co_filename
-
+ # parse stuff before comma: [filename:]lineno | function
+ colon = string.rfind(arg, ':')
+ if colon >= 0:
+ filename = string.rstrip(arg[:colon])
+ filename = self.lookupmodule(filename)
+ arg = string.lstrip(arg[colon+1:])
+ try:
+ lineno = int(arg)
+ except ValueError, msg:
+ print '*** Bad lineno:', arg
+ return
+ else:
+ # no colon; can be lineno or function
+ try:
+ lineno = int(arg)
+ except ValueError:
+ try:
+ func = eval(arg,
+ self.curframe.f_globals,
+ self.curframe.f_locals)
+ except:
+ print '*** Could not eval argument:',
+ print arg
+ return
+ try:
+ if hasattr(func, 'im_func'):
+ func = func.im_func
+ code = func.func_code
+ except:
+ print '*** The specified object',
+ print 'is not a function', arg
+ return
+ lineno = code.co_firstlineno
+ if not filename:
+ filename = code.co_filename
+ # supply default filename if necessary
+ if not filename:
+ filename = self.curframe.f_code.co_filename
# now set the break point
err = self.set_break(filename, lineno, cond)
if err: print '***', err
@@ -141,12 +174,19 @@ class Pdb(bdb.Bdb, cmd.Cmd):
if reply in ('y', 'yes'):
self.clear_all_breaks()
return
+ filename = None
+ colon = string.rfind(arg, ':')
+ if colon >= 0:
+ filename = string.rstrip(arg[:colon])
+ filename = self.lookupmodule(filename)
+ arg = string.lstrip(arg[colon+1:])
try:
- lineno = int(eval(arg))
+ lineno = int(arg)
except:
- print '*** Error in argument:', `arg`
+ print '*** Bad lineno:', `arg`
return
- filename = self.curframe.f_code.co_filename
+ if not filename:
+ filename = self.curframe.f_code.co_filename
err = self.clear_break(filename, lineno)
if err: print '***', err
do_cl = do_clear # 'c' is already an abbreviation for 'continue'
@@ -222,7 +262,6 @@ class Pdb(bdb.Bdb, cmd.Cmd):
do_rv = do_retval
def do_p(self, arg):
- self.curframe.f_globals['__privileged__'] = 1
try:
value = eval(arg, self.curframe.f_globals, \
self.curframe.f_locals)
@@ -373,13 +412,16 @@ class Pdb(bdb.Bdb, cmd.Cmd):
self.help_b()
def help_b(self):
- print """b(reak) [lineno | function] [, "condition"]
+ print """b(reak) ([file:]lineno | function) [, "condition"]
With a line number argument, set a break there in the current
file. With a function name, set a break at the entry of that
function. Without argument, list all breaks. If a second
argument is present, it is a string specifying an expression
which must evaluate to true before the breakpoint is honored.
- """
+
+ The line number may be prefixed with a filename and a colon,
+ to specify a breakpoint in another file (probably one that
+ hasn't been loaded yet). The file is searched on sys.path."""
def help_clear(self):
self.help_cl()
@@ -387,7 +429,11 @@ class Pdb(bdb.Bdb, cmd.Cmd):
def help_cl(self):
print """cl(ear) [lineno]
With a line number argument, clear that break in the current file.
- Without argument, clear all breaks (but first ask confirmation)."""
+ Without argument, clear all breaks (but first ask confirmation).
+
+ The line number may be prefixed with a filename and a colon,
+ to specify a breakpoint in another file (probably one that
+ hasn't been loaded yet). The file is searched on sys.path."""
def help_step(self):
self.help_s()
@@ -466,6 +512,19 @@ class Pdb(bdb.Bdb, cmd.Cmd):
def help_pdb(self):
help()
+ # Helper function for break/clear parsing -- may be overridden
+
+ def lookupmodule(self, filename):
+ if filename == mainmodule:
+ return mainpyfile
+ for dirname in sys.path:
+ fullname = os.path.join(dirname, filename)
+ if os.path.exists(fullname):
+ return fullname
+ print 'Warning:', `filename`, 'not found from sys.path'
+ return filename
+
+
# Simplified interface
def run(statement, globals=None, locals=None):
@@ -493,7 +552,6 @@ def post_mortem(t):
p.interaction(t.tb_frame, t)
def pm():
- import sys
post_mortem(sys.last_traceback)
@@ -506,7 +564,6 @@ def test():
# print help
def help():
- import os
for dirname in sys.path:
fullname = os.path.join(dirname, 'pdb.doc')
if os.path.exists(fullname):
@@ -517,16 +574,21 @@ 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__':
- import sys
- import os
+ global mainmodule, mainpyfile
if not sys.argv[1:]:
print "usage: pdb.py scriptfile [arg] ..."
sys.exit(2)
- filename = sys.argv[1] # Get script filename
-
+ mainpyfile = filename = sys.argv[1] # Get script filename
+ if not os.path.exists(filename):
+ print 'Error:', `filename`, '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