summaryrefslogtreecommitdiffstats
path: root/Lib/tb.py
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1990-12-26 15:40:07 (GMT)
committerGuido van Rossum <guido@python.org>1990-12-26 15:40:07 (GMT)
commit217a5fa3c33ae58c1fe420f94eeb7e806961c3c1 (patch)
treeb0bdfd34e5a72346a63106565acc7622a28b2a30 /Lib/tb.py
parent66a07c07a5b7b1ce7150d5c5c1a0998d062e452e (diff)
downloadcpython-217a5fa3c33ae58c1fe420f94eeb7e806961c3c1.zip
cpython-217a5fa3c33ae58c1fe420f94eeb7e806961c3c1.tar.gz
cpython-217a5fa3c33ae58c1fe420f94eeb7e806961c3c1.tar.bz2
Initial revision
Diffstat (limited to 'Lib/tb.py')
-rw-r--r--Lib/tb.py220
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