]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Initial revision
authorGuido van Rossum <guido@python.org>
Fri, 10 Jan 1992 14:54:42 +0000 (14:54 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 10 Jan 1992 14:54:42 +0000 (14:54 +0000)
Lib/linecache.py [new file with mode: 0644]
Lib/pdb.py [new file with mode: 0755]

diff --git a/Lib/linecache.py b/Lib/linecache.py
new file mode 100644 (file)
index 0000000..4355f19
--- /dev/null
@@ -0,0 +1,71 @@
+# Cache lines from files.
+
+import os
+from stat import *
+
+def getline(filename, lineno):
+       lines = getlines(filename)
+       if 1 <= lineno <= len(lines):
+               return lines[lineno-1]
+       else:
+               return ''
+
+
+# The cache
+
+cache = {} # The cache
+
+
+# Clear the cache entirely
+
+def clearcache():
+       global cache
+       cache = {}
+
+
+# Get the lines for a file from the cache.
+# Update the cache if it doesn't contain an entry for this file already.
+
+def getlines(filename):
+       if cache.has_key(filename):
+               return cache[filename][2]
+       else:
+               return updatecache(filename)
+
+
+# Discard cache entries that are out of date.
+# (This is not checked upon each call
+
+def checkcache():
+       for filename in cache.keys():
+               size, mtime, lines = cache[filename]
+               try:    stat = os.stat(filename)
+               except os.error:
+                       del cache[filename]
+                       continue
+               if size <> stat[ST_SIZE] or mtime <> stat[ST_MTIME]:
+                       del cache[filename]
+
+
+# Update a cache entry and return its list of lines.
+# If something's wrong, print a message, discard the cache entry,
+# and return an empty list.
+
+def updatecache(filename):
+       try:    del cache[filename]
+       except KeyError: pass
+       try:    stat = os.stat(filename)
+       except os.error, msg:
+               if filename[0] + filename[-1] <> '<>':
+                       print '*** Cannot stat', filename, ':', msg
+               return []
+       try:
+               fp = open(filename, 'r')
+               lines = fp.readlines()
+               fp.close()
+       except IOError, msg:
+               print '*** Cannot open', filename, ':', msg
+               return []
+       size, mtime = stat[ST_SIZE], stat[ST_MTIME]
+       cache[filename] = size, mtime, lines
+       return lines
diff --git a/Lib/pdb.py b/Lib/pdb.py
new file mode 100755 (executable)
index 0000000..259c770
--- /dev/null
@@ -0,0 +1,396 @@
+# pdb.py -- finally, a Python debugger!
+
+# To do:
+# - Keep a list of exceptions trapped (default only KeyboardInterrupt?)
+# - A blank line should repeat the previous command, not execute 'next'
+# - Don't line-trace functions (or at least files) without breakpoints
+# - Better handling of call/return events
+# - It should be possible to intercept KeyboardInterrupt completely
+# - Where and when to stop exactly when 'next' encounters a return?
+#   (should be level-based -- don't trace anything deeper than current)
+# - Show stack traces upside-down (like dbx/gdb)
+
+import string
+import sys
+import linecache
+
+
+# A generic class to build command interpreters
+
+PROMPT = '(Cmd) '
+IDENTCHARS = string.letters + string.digits + '_'
+
+class Cmd:
+       def init(self):
+               self.prompt = PROMPT
+               self.identchars = IDENTCHARS
+               return self
+       def commandloop(self):
+               try:
+                       self.innerloop()
+               except EOFError:
+                       pass
+       def innerloop(self):
+               while 1:
+                       line = string.strip(self.getline())
+                       self.execline(line)
+       def execline(self, line):
+               i, n = 0, len(line)
+               while i < n and line[i] in self.identchars: i = i+1
+               cmd, arg = line[:i], string.strip(line[i:])
+               if cmd == '':
+                       self.default(line)
+               else:
+                       try:
+                               func = eval('self.do_' + cmd)
+                       except AttributeError:
+                               self.default(line)
+                               return
+                       func(arg)
+       def getline(self):
+               return raw_input(self.prompt)
+       def default(self, line):
+               print '*** Unknown syntax:', line
+       def do_help(self, arg):
+               if arg:
+                       # XXX check arg syntax
+                       try:
+                               func = eval('self.help_' + arg)
+                       except:
+                               print '*** No help on', `arg`
+                               return
+                       func()
+               else:
+                       import getattr
+                       names = getattr.dir(self)
+                       cmds = []
+                       for name in names:
+                               if name[:3] == 'do_':
+                                       cmds.append(name[3:])
+                       print cmds
+
+
+# A specialization of Cmd for use by the debugger
+
+PdbDone = 'PdbDone' # Exception used internally
+PdbQuit = 'PdbQuit' # Exception to just give up
+
+class Pdb(Cmd):
+       
+       def init(self):
+               self = Cmd.init(self)
+               self.prompt = '(Pdb) '
+               self.reset()
+               self.breaks = {}
+               return self
+       
+       def reset(self):
+               self.whatnext = ''
+               self.botframe = None
+               self.forget()
+       
+       def forget(self):
+               self.curframe = self.topframe = None
+               self.stack = []
+               self.lineno = None
+       
+       def setup(self, frame):
+               self.curframe = self.topframe = frame
+               self.stack = []
+               self.lineno = None
+               self.stopframe = None
+               self.whatnext = ''
+       
+       def run(self, cmd):
+               if cmd[-1:] != '\n': cmd = cmd + '\n'
+               self.reset()
+               sys.trace = self.dispatch
+               try:
+                       exec(cmd)
+               except PdbQuit:
+                       pass
+               finally:
+                       sys.trace = None
+                       del sys.trace
+                       self.reset()
+       
+       def dispatch(self, frame, where, arg):
+               if self.whatnext == 'quit':
+                       return
+               if self.botframe is None:
+                       self.botframe = frame
+               if where == 'exception':
+                       stop = 1
+               elif self.whatnext == 'continue':
+                       stop = 0
+               elif self.whatnext == 'next':
+                       stop = (frame == self.stopframe)
+               else:
+                       stop = 1
+               if not stop:
+                       # Check breakpoints only
+                       filename = frame.f_code.co_filename
+                       if not self.breaks.has_key(filename):
+                               return self.dispatch
+                       lineno = frame.f_lineno
+                       if lineno not in self.breaks[filename]:
+                               return self.dispatch
+               if where == 'call':
+                       print 'call arguments:', arg
+               elif where == 'return':
+                       print 'return value:', arg
+               elif where == 'exception':
+                       print 'exception:', arg[:2]
+               elif where != 'line':
+                       print 'unknown trace type:', `where`
+               self.setup(frame)
+               try:
+                       self.whatnext = self.commandloop()
+               finally:
+                       self.forget()
+               if self.whatnext == 'quit':
+                       raise PdbQuit
+               if self.whatnext == 'next':
+                       if where != 'return':
+                               self.stopframe = frame
+                       else:
+                               self.whatnext = 'step'
+               return self.dispatch
+       
+       def commandloop(self):
+               self.printwhere(self.curframe)
+               try:
+                       self.innerloop()
+               except EOFError:
+                       self.do_next('')
+               except PdbDone, msg:
+                       return msg
+       
+       def default(self, line):
+               if not line:
+                       self.do_next('')
+               else:
+                       if line[0] == '!': line = line[1:]
+                       try:
+                               exec(line + '\n', \
+                                       self.curframe.f_globals, \
+                                       self.curframe.f_locals)
+                       except:
+                               print '***', sys.exc_type + ':',
+                               print `sys.exc_value`
+       
+       do_h = Cmd.do_help
+       
+       def do_break(self, arg):
+               if not arg:
+                       print self.breaks # XXX
+                       return
+               try:
+                       lineno = int(eval(arg))
+               except:
+                       print '*** Error in argument:', `arg`
+                       return
+               filename = self.curframe.f_code.co_filename
+               line = linecache.getline(filename, lineno)
+               if not line:
+                       print '*** That line does not exist!'
+                       return
+               if not self.breaks.has_key(filename):
+                       self.breaks[filename] = []
+               list = self.breaks[filename]
+               if lineno in list:
+                       print '*** There is already a break there!'
+                       return
+               list.append(lineno)
+       do_b = do_break
+       
+       def do_clear(self, arg):
+               if not arg:
+                       self.breaks = {}
+                       print 'All breaks cleared!'
+                       return
+               try:
+                       lineno = int(eval(arg))
+               except:
+                       print '*** Error in argument:', `arg`
+                       return
+               filename = self.curframe.f_code.co_filename
+               try:
+                       self.breaks[filename].remove(lineno)
+                       if self.breaks[filename] == []:
+                               del self.breaks[filename]
+               except (ValueError, KeyError):
+                       print '*** There is no break there!'
+                       return
+       
+       def do_where(self, arg):
+               self.printtb()
+       do_w = do_where
+       
+       def do_up(self, arg):
+               if not self.stack: print '*** Top'
+               else:
+                       self.curframe = self.stack[-1]
+                       self.lineno = None
+                       del self.stack[-1]
+                       self.printwhere(self.curframe)
+       do_u = do_up
+       
+       def do_down(self, arg):
+               if self.curframe == self.botframe or \
+                       not self.curframe.f_back: print '*** Bottom'
+               else:
+                       self.stack.append(self.curframe)
+                       self.curframe = self.curframe.f_back
+                       self.lineno = None
+                       self.printwhere(self.curframe)
+       do_d = do_down
+       
+       def do_step(self, arg):
+               raise PdbDone, 'step'
+       do_s = do_step
+       
+       def do_next(self, arg):
+               raise PdbDone, 'next'
+       do_n = do_next
+       
+       def do_continue(self, arg):
+               raise PdbDone, 'continue'
+       do_c = do_cont = do_continue
+       
+       def do_quit(self, arg):
+               raise PdbDone, 'quit'
+       do_q = do_quit
+       
+       def do_list(self, arg):
+               last = None
+               if arg:
+                       try:
+                               x = eval(arg, {}, {})
+                               if type(x) == type(()):
+                                       first, last = x
+                                       first = int(first)
+                                       last = int(last)
+                                       if last < first:
+                                               # Assume it's a count
+                                               last = first + last
+                               else:
+                                       first = int(x)
+                       except:
+                               print '*** Error in argument:', `arg`
+                               return
+               elif self.lineno is None:
+                       first = max(1, self.curframe.f_lineno - 5)
+               else:
+                       first = self.lineno + 1
+               if last is None:
+                       last = first + 10
+               filename = self.curframe.f_code.co_filename
+               if self.breaks.has_key(filename):
+                       breaklist = self.breaks[filename]
+               else:
+                       breaklist = []
+               try:
+                       for lineno in range(first, last+1):
+                               line = linecache.getline(filename, lineno)
+                               if not line:
+                                       print '[EOF]'
+                                       break
+                               else:
+                                       s = string.rjust(`lineno`, 3)
+                                       if len(s) < 4: s = s + ' '
+                                       if lineno in breaklist: s = s + 'B'
+                                       else: s = s + ' '
+                                       if lineno == self.curframe.f_lineno:
+                                               s = s + '->'
+                                       print s + '\t' + line,
+                                       self.lineno = lineno
+               except KeyboardInterrupt:
+                       pass
+       do_l = do_list
+
+       # Print a traceback starting at a given stack frame
+       # Note that it is printed upside-down with respect
+       # to the orientation suggested by the up/down commands.
+       # This is consistent with gdb.
+       def printtb(self):
+               list = []
+               frame = self.topframe
+               while frame:
+                       list.append(frame)
+                       if frame is self.botframe: break
+                       frame = frame.f_back
+               list.reverse()
+               for frame in list:
+                       self.printwhere(frame)
+       
+       def printwhere(self, frame):
+               if frame is self.curframe: print '->',
+               code = frame.f_code
+               filename = code.co_filename
+               lineno = frame.f_lineno
+               print filename + '(' + `lineno` + ')',
+               line = linecache.getline(filename, lineno)
+               if line: print string.strip(line),
+               print
+
+
+# --------------------- testing ---------------------
+
+# The Ackermann function -- a highly recursive beast
+cheat = 0
+cache = {}
+def ack(x, y):
+       key = `(long(x), long(y))`
+       if cache.has_key(key):
+               res = cache[key]
+       else:
+               if x == 0:
+                       res = 1L
+               elif y == 0:
+                       if x == 1:
+                               res = 2L
+                       else:
+                               res = 2L + x
+               elif y == 1 and cheat >= 1:
+                       res = 2L * x
+               elif y == 2 and cheat >= 2:
+                       res = pow(2L, x)
+               else:
+                       res = ack(ack(x-1, y), y-1)
+               cache[key] = res
+       return res
+
+def foo(n):
+       print 'foo', n
+       x = bar(n*2)
+       print 'bar returned', x
+       return
+
+def bar(a):
+       print 'bar', a
+       return a*10
+
+def test():
+       linecache.checkcache()
+       Pdb().init().run('foo(12)')
+
+
+# --------------------- main ---------------------
+
+import os
+
+def main():
+       if sys.argv[1:]:
+               file = sys.argv[1]
+               head, tail = os.path.split(file)
+               if tail[-3:] != '.py':
+                       print 'Sorry, file arg must be a python module'
+                       print '(i.e., must end in \'.py\')'
+                       # XXX Or we could copy it to a temp file
+                       sys.exit(2)
+               del sys.argv[0]
+               sys.path.insert(0, head)
+               Pdb().init().run('import ' + tail[:-3])
+       else:
+               Pdb().init().run('')