summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1992-01-27 16:58:47 (GMT)
committerGuido van Rossum <guido@python.org>1992-01-27 16:58:47 (GMT)
commit23efba4cd1b28ac335371980f51b7ba6a77c6938 (patch)
tree8611985a674254789d83772ff173613be0868c55
parent576136044c54a922d5af3b615e24351e6501e5ee (diff)
downloadcpython-23efba4cd1b28ac335371980f51b7ba6a77c6938.zip
cpython-23efba4cd1b28ac335371980f51b7ba6a77c6938.tar.gz
cpython-23efba4cd1b28ac335371980f51b7ba6a77c6938.tar.bz2
Rewritten to use bdb.Bdb as base class.
-rwxr-xr-xLib/pdb.py385
1 files changed, 99 insertions, 286 deletions
diff --git a/Lib/pdb.py b/Lib/pdb.py
index da3cd7d..0dd975b 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -1,194 +1,83 @@
# pdb.py -- finally, a Python debugger!
-# See file pdb.doc for instructions.
-
-# To do:
-# - It should be possible to intercept KeyboardInterrupt
-# - Handle return events differently -- always printing the r.v. can be bad!
-# - Merge with tb, to get a single debugger for active and post-mortem usage
-# - Solve bugs in termination (e.g., 'continue' after the program
-# is done proceeds to debug the debugger; 'quit' sometimes complains
-# about the PdbQuit exception...)
+# (See pdb.doc for documentation.)
import string
import sys
import linecache
-from cmd import Cmd
-
-
-# A specialization of Cmd for use by the debugger
+import cmd
+import bdb
+import repr
-PdbQuit = 'pdb.PdbQuit' # Exception to give up
-class Pdb(Cmd):
+class Pdb(bdb.Bdb, cmd.Cmd):
def init(self):
- self = Cmd.init(self)
+ self = bdb.Bdb.init(self)
+ self = cmd.Cmd.init(self)
self.prompt = '(Pdb) '
- self.reset()
return self
def reset(self):
- self.quitting = 0
- self.breaks = {}
- self.botframe = None
- self.stopframe = None
- self.lastretval = None
+ bdb.Bdb.reset(self)
self.forget()
def forget(self):
- self.setup(None, None)
-
- def setup(self, f, t):
self.lineno = None
self.stack = []
self.curindex = 0
self.curframe = None
- if f is None and t is None:
- return
- if t and t.tb_frame is f:
- t = t.tb_next
- while f is not None:
- self.stack.append((f, f.f_lineno))
- if f is self.botframe:
- break
- f = f.f_back
- else:
- print '[Weird: bottom frame not in stack trace.]'
- self.stack.reverse()
- self.curindex = max(0, len(self.stack) - 1)
- while t is not None:
- self.stack.append((t.tb_frame, t.tb_lineno))
- t = t.tb_next
- self.curframe = self.stack[self.curindex][0]
-
- def run(self, cmd):
- import __main__
- dict = __main__.__dict__
- self.runctx(cmd, dict, dict)
- def runctx(self, cmd, globals, locals):
- t = None
- self.reset()
- sys.trace = self.dispatch
- try:
- exec(cmd + '\n', globals, locals)
- except PdbQuit:
- return
- except:
- print '***', sys.exc_type + ':', `sys.exc_value`
- t = sys.exc_traceback
- finally:
- self.trace = None
- del self.trace
- self.forget()
- print '!!! Post-mortem debugging'
- self.pmd(t)
-
- def pmd(self, traceback):
- t = traceback
- if self.botframe is not None:
- while t is not None:
- if t.tb_frame is not self.botframe:
- break
- t = t.tb_next
- else:
- t = sys.exc_traceback
- try:
- self.ask_user(self.botframe, t)
- except PdbQuit:
- pass
- finally:
- self.forget()
-
- def dispatch(self, frame, event, arg):
- if self.quitting:
- return None
- if event == 'line':
- return self.dispatch_line(frame)
- if event == 'call':
- return self.dispatch_call(frame, arg)
- if event == 'return':
- return self.dispatch_return(frame, arg)
- if event == 'exception':
- return self.dispatch_exception(frame, arg)
- print '*** dispatch: unknown event type', `event`
- return self.dispatch
-
- def dispatch_line(self, frame):
- if self.stop_here(frame) or self.break_here(frame):
- self.ask_user(frame, None)
- return self.dispatch
-
- def dispatch_call(self, frame, arg):
- if self.botframe is None:
- # First call dispatch since reset()
- self.botframe = frame
- return None
- if not (self.stop_here(frame) or self.break_anywhere(frame)):
- return None
- if arg is None:
- print '[Entering non-function block.]'
- else:
- frame.f_locals['__args__'] = arg
- return self.dispatch
+ def setup(self, f, t):
+ self.forget()
+ self.stack, self.curindex = self.get_stack(f, t)
+ self.curframe = self.stack[self.curindex][0]
- def dispatch_return(self, frame, arg):
- self.lastretval = arg
- return None
+ # Override Bdb methods (except user_call, for now)
- def dispatch_exception(self, frame, arg):
- if self.stop_here(frame):
- print '!!!', arg[0] + ':', `arg[1]`
- self.ask_user(frame, arg[2])
- return self.dispatch
+ def user_line(self, frame):
+ # This function is called when we stop or break at this line
+ self.interaction(frame, None)
- def stop_here(self, frame):
- if self.stopframe is None:
- return 1
- if frame is self.stopframe:
- return 1
- while frame is not None and frame is not self.stopframe:
- if frame is self.botframe:
- return 1
- frame = frame.f_back
- return 0
+ def user_return(self, frame, return_value):
+ # This function is called when a return trap is set here
+ frame.f_locals['__return__'] = return_value
+ print '--Return--'
+ self.interaction(frame, None)
- def break_here(self, frame):
- if not self.breaks.has_key(frame.f_code.co_filename):
- return 0
- if not frame.f_lineno in \
- self.breaks[frame.f_code.co_filename]:
- return 0
- return 1
+ def user_exception(self, frame, (exc_type, exc_value, exc_traceback)):
+ # This function is called if an exception occurs,
+ # but only if we are to stop at or just below this level
+ frame.f_locals['__exception__'] = exc_type, exc_value
+ print exc_type + ':', repr.repr(exc_value)
+ self.interaction(frame, exc_traceback)
- def break_anywhere(self, frame):
- return self.breaks.has_key(frame.f_code.co_filename)
+ # General interaction function
- def ask_user(self, frame, traceback):
+ def interaction(self, frame, traceback):
self.setup(frame, traceback)
- self.printframelineno(self.stack[self.curindex])
+ self.print_stack_entry(self.stack[self.curindex])
self.cmdloop()
self.forget()
-
+
def default(self, line):
- if not line:
- return 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`
+ if line[:1] == '!': line = line[1:]
+ locals = self.curframe.f_locals
+ globals = self.curframe.f_globals
+ try:
+ exec(line + '\n', globals, locals)
+ except:
+ print '***', sys.exc_type + ':', sys.exc_value
+
+ # Command definitions, called by cmdloop()
+ # The argument is the remaining string on the command line
+ # Return true to exit from the command loop
- do_h = Cmd.do_help
+ do_h = cmd.Cmd.do_help
def do_break(self, arg):
if not arg:
- print self.breaks # XXX
+ print self.get_all_breaks() # XXX
return
try:
lineno = int(eval(arg))
@@ -196,17 +85,8 @@ class Pdb(Cmd):
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)
+ err = self.set_break(filename, lineno)
+ if err: print '***', err
do_b = do_break
def do_clear(self, arg):
@@ -217,7 +97,7 @@ class Pdb(Cmd):
reply = 'no'
reply = string.lower(string.strip(reply))
if reply in ('y', 'yes'):
- self.breaks = {}
+ self.clear_all_breaks()
return
try:
lineno = int(eval(arg))
@@ -225,17 +105,12 @@ class Pdb(Cmd):
print '*** Error in argument:', `arg`
return
filename = self.curframe.f_code.co_filename
- try:
- self.breaks[filename].remove(lineno)
- except (ValueError, KeyError):
- print '*** There is no break there!'
- return
- if not self.breaks[filename]:
- del self.breaks[filename]
+ err = self.set_break(filename, lineno)
+ if err: print '***', err
do_cl = do_clear # 'c' is already an abbreviation for 'continue'
def do_where(self, arg):
- self.printstacktrace()
+ self.print_stack_trace()
do_w = do_where
def do_up(self, arg):
@@ -244,7 +119,7 @@ class Pdb(Cmd):
else:
self.curindex = self.curindex - 1
self.curframe = self.stack[self.curindex][0]
- self.printframelineno(self.stack[self.curindex])
+ self.print_stack_entry(self.stack[self.curindex])
do_u = do_up
def do_down(self, arg):
@@ -253,39 +128,57 @@ class Pdb(Cmd):
else:
self.curindex = self.curindex + 1
self.curframe = self.stack[self.curindex][0]
- self.printframelineno(self.stack[self.curindex])
+ self.print_stack_entry(self.stack[self.curindex])
do_d = do_down
def do_step(self, arg):
- self.stopframe = None
+ self.set_step()
return 1
do_s = do_step
def do_next(self, arg):
- self.stopframe = self.curframe
+ self.set_next(self.curframe)
return 1
do_n = do_next
def do_return(self, arg):
- self.stopframe = self.curframe.f_back
+ self.set_return(self.curframe)
return 1
do_r = do_return
- def do_retval(self, arg):
- print self.lastretval
- do_rv = do_retval
-
def do_continue(self, arg):
- self.stopframe = self.botframe
+ self.set_continue()
return 1
do_c = do_cont = do_continue
def do_quit(self, arg):
- self.quitting = 1
- sys.trace = None; del sys.trace
- raise PdbQuit
+ self.set_quit()
+ return 1
do_q = do_quit
+ def do_args(self, arg):
+ if self.curframe.f_locals.has_key('__return__'):
+ print `self.curframe.f_locals['__return__']`
+ else:
+ print '*** Not arguments?!'
+ do_a = do_args
+
+ def do_retval(self, arg):
+ if self.curframe.f_locals.has_key('__return__'):
+ print self.curframe.f_locals['__return__']
+ else:
+ print '*** Not yet returned!'
+ do_rv = do_retval
+
+ def do_p(self, arg):
+ try:
+ value = eval(arg, self.curframe.f_globals, \
+ self.curframe.f_locals)
+ except:
+ print '***', sys.exc_type + ':', `sys.exc_value`
+ return
+ print `value`
+
def do_list(self, arg):
self.lastcmd = 'list'
last = None
@@ -311,10 +204,7 @@ class Pdb(Cmd):
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 = []
+ breaklist = self.get_file_breaks(filename)
try:
for lineno in range(first, last+1):
line = linecache.getline(filename, lineno)
@@ -334,45 +224,28 @@ class Pdb(Cmd):
pass
do_l = do_list
- def do_args(self, arg):
- try:
- value = eval('__args__', self.curframe.f_globals, \
- self.curframe.f_locals)
- except:
- print '***', sys.exc_type + ':', `sys.exc_value`
- return
- print `value`
- do_a = do_args
-
- def do_p(self, arg):
- try:
- value = eval(arg, self.curframe.f_globals, \
- self.curframe.f_locals)
- except:
- print '***', sys.exc_type + ':', `sys.exc_value`
- return
- print `value`
-
# Print a traceback starting at the top stack frame.
- # Note that the most recently entered frame is printed last;
+ # The most recently entered frame is printed last;
# this is different from dbx and gdb, but consistent with
# the Python interpreter's stack trace.
# It is also consistent with the up/down commands (which are
# compatible with dbx and gdb: up moves towards 'main()'
# and down moves towards the most recent stack frame).
- def printstacktrace(self):
- for x in self.stack:
- self.printframelineno(x)
+ def print_stack_trace(self):
+ try:
+ for frame_lineno in self.stack:
+ self.print_stack_entry(frame_lineno)
+ except KeyboardInterrupt:
+ pass
- def printframelineno(self, (frame, lineno)):
- if frame is self.curframe: print '->',
- code = frame.f_code
- filename = code.co_filename
- print filename + '(' + `lineno` + ')',
- line = linecache.getline(filename, lineno)
- print string.strip(line),
- print
+ def print_stack_entry(self, frame_lineno):
+ frame, lineno = frame_lineno
+ if frame is self.curframe:
+ print '>',
+ else:
+ print ' ',
+ print self.format_stack_entry(frame_lineno)
def run(statement):
@@ -381,69 +254,9 @@ def run(statement):
def runctx(statement, globals, locals):
Pdb().init().runctx(statement, globals, locals)
-
-# --------------------- testing ---------------------
-
-# The Ackermann function -- a highly recursive beast
-cheat = 2
-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
- y = ack(4, 3)
- return y
-
-def bar(a):
- print 'bar', a
- return a*10
-
-def melt(n):
- print 1.0/n
- melt(n-1)
+TESTCMD = 'import x; x.main()'
def test():
+ import linecache
linecache.checkcache()
- runctx('from pdb import foo; foo(12)', {}, {})
- runctx('from pdb import melt; melt(5)', {}, {})
-
-
-# --------------------- 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)
- run('import ' + tail[:-3])
- else:
- run(raw_input('Python statement to debug: '))
+ run(TESTCMD)