diff options
author | Guido van Rossum <guido@python.org> | 1990-12-26 15:40:07 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1990-12-26 15:40:07 (GMT) |
commit | 217a5fa3c33ae58c1fe420f94eeb7e806961c3c1 (patch) | |
tree | b0bdfd34e5a72346a63106565acc7622a28b2a30 /Lib/tb.py | |
parent | 66a07c07a5b7b1ce7150d5c5c1a0998d062e452e (diff) | |
download | cpython-217a5fa3c33ae58c1fe420f94eeb7e806961c3c1.zip cpython-217a5fa3c33ae58c1fe420f94eeb7e806961c3c1.tar.gz cpython-217a5fa3c33ae58c1fe420f94eeb7e806961c3c1.tar.bz2 |
Initial revision
Diffstat (limited to 'Lib/tb.py')
-rw-r--r-- | Lib/tb.py | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/Lib/tb.py b/Lib/tb.py new file mode 100644 index 0000000..e0f2748 --- /dev/null +++ b/Lib/tb.py @@ -0,0 +1,220 @@ +# Print tracebacks, with a dump of local variables. +# Also an interactive stack trace browser. + +import sys +try: + import mac + os = mac +except NameError: + import posix + os = posix +from stat import * +import string + +def br(): browser(sys.last_traceback) + +def tb(): printtb(sys.last_traceback) + +def browser(tb): + if not tb: + print 'No traceback.' + return + tblist = [] + while tb: + tblist.append(tb) + tb = tb.tb_next + ptr = len(tblist)-1 + tb = tblist[ptr] + while 1: + if tb <> tblist[ptr]: + tb = tblist[ptr] + print `ptr` + ':', + printtbheader(tb) + try: + line = raw_input('TB: ') + except KeyboardInterrupt: + print '\n[Interrupted]' + break + except EOFError: + print '\n[EOF]' + break + cmd = string.strip(line) + if cmd: + if cmd = 'quit': + break + elif cmd = 'list': + browserlist(tb) + elif cmd = 'up': + if ptr-1 >= 0: ptr = ptr-1 + else: print 'Bottom of stack.' + elif cmd = 'down': + if ptr+1 < len(tblist): ptr = ptr+1 + else: print 'Top of stack.' + elif cmd = 'locals': + printsymbols(tb.tb_frame.f_locals) + elif cmd = 'globals': + printsymbols(tb.tb_frame.f_globals) + elif cmd in ('?', 'help'): + browserhelp() + else: + browserexec(tb, cmd) + +def browserlist(tb): + filename = tb.tb_frame.f_code.co_filename + lineno = tb.tb_lineno + last = lineno + first = max(1, last-10) + for i in range(first, last+1): + if i = lineno: prefix = '***' + string.rjust(`i`, 4) + ':' + else: prefix = string.rjust(`i`, 7) + ':' + line = readfileline(filename, i) + if line[-1:] = '\n': line = line[:-1] + print prefix + line + +def browserexec(tb, cmd): + locals = tb.tb_frame.f_locals + globals = tb.tb_frame.f_globals + try: + exec(cmd+'\n', globals, locals) + except: + print '*** Exception:', + print sys.exc_type, + if sys.exc_value <> None: + print ':', sys.exc_value, + print + print 'Type help to get help.' + +def browserhelp(): + print + print ' This is the traceback browser. Commands are:' + print ' up : move one level up in the call stack' + print ' down : move one level down in the call stack' + print ' locals : print all local variables at this level' + print ' globals : print all global variables at this level' + print ' list : list source code around the failure' + print ' help : print help (what you are reading now)' + print ' quit : back to command interpreter' + print ' Typing any other 1-line statement will execute it' + print ' using the current level\'s symbol tables' + print + +def printtb(tb): + while tb: + print1tb(tb) + tb = tb.tb_next + +def print1tb(tb): + printtbheader(tb) + if tb.tb_frame.f_locals is not tb.tb_frame.f_globals: + printsymbols(tb.tb_frame.f_locals) + +def printtbheader(tb): + filename = tb.tb_frame.f_code.co_filename + lineno = tb.tb_lineno + info = '"' + filename + '"(' + `lineno` + ')' + line = readfileline(filename, lineno) + if line: + info = info + ': ' + string.strip(line) + print info + +def printsymbols(d): + keys = d.keys() + keys.sort() + for name in keys: + print ' ' + string.ljust(name, 12) + ':', + printobject(d[name], 4) + print + +def printobject(v, maxlevel): + if v = None: + print 'None', + elif type(v) in (type(0), type(0.0)): + print v, + elif type(v) = type(''): + if len(v) > 20: + print `v[:17] + '...'`, + else: + print `v`, + elif type(v) = type(()): + print '(', + printlist(v, maxlevel) + print ')', + elif type(v) = type([]): + print '[', + printlist(v, maxlevel) + print ']', + elif type(v) = type({}): + print '{', + printdict(v, maxlevel) + print '}', + else: + print v, + +def printlist(v, maxlevel): + n = len(v) + if n = 0: return + if maxlevel <= 0: + print '...', + return + for i in range(min(6, n)): + printobject(v[i], maxlevel-1) + if i+1 < n: print ',', + if n > 6: print '...', + +def printdict(v, maxlevel): + keys = v.keys() + n = len(keys) + if n = 0: return + if maxlevel <= 0: + print '...', + return + keys.sort() + for i in range(min(6, n)): + key = keys[i] + print `key` + ':', + printobject(v[key], maxlevel-1) + if i+1 < n: print ',', + if n > 6: print '...', + +_filecache = {} + +def readfileline(filename, lineno): + try: + stat = os.stat(filename) + except os.error, msg: + print 'Cannot stat', filename, '--', msg + return '' + cache_ok = 0 + if _filecache.has_key(filename): + cached_stat, lines = _filecache[filename] + if stat[ST_SIZE] = cached_stat[ST_SIZE] and \ + stat[ST_MTIME] = cached_stat[ST_MTIME]: + cache_ok = 1 + else: + print 'Stale cache entry for', filename + del _filecache[filename] + if not cache_ok: + lines = readfilelines(filename) + if not lines: + return '' + _filecache[filename] = stat, lines + if 0 <= lineno-1 < len(lines): + return lines[lineno-1] + else: + print 'Line number out of range, last line is', len(lines) + return '' + +def readfilelines(filename): + try: + fp = open(filename, 'r') + except: + print 'Cannot open', filename + return [] + lines = [] + while 1: + line = fp.readline() + if not line: break + lines.append(line) + if not lines: + print 'Empty file', filename + return lines |