]> granicus.if.org Git - python/commitdiff
Added support for specifying a filename for a breakpoint, roughly
authorGuido van Rossum <guido@python.org>
Mon, 20 Jul 1998 23:13:54 +0000 (23:13 +0000)
committerGuido van Rossum <guido@python.org>
Mon, 20 Jul 1998 23:13:54 +0000 (23:13 +0000)
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.

Lib/pdb.py

index 80aa54bf52d72adb6077bfd299dfb52735ab9e9d..2824f4c22d3969e2a248538b0f1e81dd5b30353a 100755 (executable)
@@ -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