blob: e0f274897dd780cd5b9d0123a405537125dc160c [file] [log] [blame]
Guido van Rossum217a5fa1990-12-26 15:40:07 +00001# Print tracebacks, with a dump of local variables.
2# Also an interactive stack trace browser.
3
4import sys
5try:
6 import mac
7 os = mac
8except NameError:
9 import posix
10 os = posix
11from stat import *
12import string
13
14def br(): browser(sys.last_traceback)
15
16def tb(): printtb(sys.last_traceback)
17
18def browser(tb):
19 if not tb:
20 print 'No traceback.'
21 return
22 tblist = []
23 while tb:
24 tblist.append(tb)
25 tb = tb.tb_next
26 ptr = len(tblist)-1
27 tb = tblist[ptr]
28 while 1:
29 if tb <> tblist[ptr]:
30 tb = tblist[ptr]
31 print `ptr` + ':',
32 printtbheader(tb)
33 try:
34 line = raw_input('TB: ')
35 except KeyboardInterrupt:
36 print '\n[Interrupted]'
37 break
38 except EOFError:
39 print '\n[EOF]'
40 break
41 cmd = string.strip(line)
42 if cmd:
43 if cmd = 'quit':
44 break
45 elif cmd = 'list':
46 browserlist(tb)
47 elif cmd = 'up':
48 if ptr-1 >= 0: ptr = ptr-1
49 else: print 'Bottom of stack.'
50 elif cmd = 'down':
51 if ptr+1 < len(tblist): ptr = ptr+1
52 else: print 'Top of stack.'
53 elif cmd = 'locals':
54 printsymbols(tb.tb_frame.f_locals)
55 elif cmd = 'globals':
56 printsymbols(tb.tb_frame.f_globals)
57 elif cmd in ('?', 'help'):
58 browserhelp()
59 else:
60 browserexec(tb, cmd)
61
62def browserlist(tb):
63 filename = tb.tb_frame.f_code.co_filename
64 lineno = tb.tb_lineno
65 last = lineno
66 first = max(1, last-10)
67 for i in range(first, last+1):
68 if i = lineno: prefix = '***' + string.rjust(`i`, 4) + ':'
69 else: prefix = string.rjust(`i`, 7) + ':'
70 line = readfileline(filename, i)
71 if line[-1:] = '\n': line = line[:-1]
72 print prefix + line
73
74def browserexec(tb, cmd):
75 locals = tb.tb_frame.f_locals
76 globals = tb.tb_frame.f_globals
77 try:
78 exec(cmd+'\n', globals, locals)
79 except:
80 print '*** Exception:',
81 print sys.exc_type,
82 if sys.exc_value <> None:
83 print ':', sys.exc_value,
84 print
85 print 'Type help to get help.'
86
87def browserhelp():
88 print
89 print ' This is the traceback browser. Commands are:'
90 print ' up : move one level up in the call stack'
91 print ' down : move one level down in the call stack'
92 print ' locals : print all local variables at this level'
93 print ' globals : print all global variables at this level'
94 print ' list : list source code around the failure'
95 print ' help : print help (what you are reading now)'
96 print ' quit : back to command interpreter'
97 print ' Typing any other 1-line statement will execute it'
98 print ' using the current level\'s symbol tables'
99 print
100
101def printtb(tb):
102 while tb:
103 print1tb(tb)
104 tb = tb.tb_next
105
106def print1tb(tb):
107 printtbheader(tb)
108 if tb.tb_frame.f_locals is not tb.tb_frame.f_globals:
109 printsymbols(tb.tb_frame.f_locals)
110
111def printtbheader(tb):
112 filename = tb.tb_frame.f_code.co_filename
113 lineno = tb.tb_lineno
114 info = '"' + filename + '"(' + `lineno` + ')'
115 line = readfileline(filename, lineno)
116 if line:
117 info = info + ': ' + string.strip(line)
118 print info
119
120def printsymbols(d):
121 keys = d.keys()
122 keys.sort()
123 for name in keys:
124 print ' ' + string.ljust(name, 12) + ':',
125 printobject(d[name], 4)
126 print
127
128def printobject(v, maxlevel):
129 if v = None:
130 print 'None',
131 elif type(v) in (type(0), type(0.0)):
132 print v,
133 elif type(v) = type(''):
134 if len(v) > 20:
135 print `v[:17] + '...'`,
136 else:
137 print `v`,
138 elif type(v) = type(()):
139 print '(',
140 printlist(v, maxlevel)
141 print ')',
142 elif type(v) = type([]):
143 print '[',
144 printlist(v, maxlevel)
145 print ']',
146 elif type(v) = type({}):
147 print '{',
148 printdict(v, maxlevel)
149 print '}',
150 else:
151 print v,
152
153def printlist(v, maxlevel):
154 n = len(v)
155 if n = 0: return
156 if maxlevel <= 0:
157 print '...',
158 return
159 for i in range(min(6, n)):
160 printobject(v[i], maxlevel-1)
161 if i+1 < n: print ',',
162 if n > 6: print '...',
163
164def printdict(v, maxlevel):
165 keys = v.keys()
166 n = len(keys)
167 if n = 0: return
168 if maxlevel <= 0:
169 print '...',
170 return
171 keys.sort()
172 for i in range(min(6, n)):
173 key = keys[i]
174 print `key` + ':',
175 printobject(v[key], maxlevel-1)
176 if i+1 < n: print ',',
177 if n > 6: print '...',
178
179_filecache = {}
180
181def readfileline(filename, lineno):
182 try:
183 stat = os.stat(filename)
184 except os.error, msg:
185 print 'Cannot stat', filename, '--', msg
186 return ''
187 cache_ok = 0
188 if _filecache.has_key(filename):
189 cached_stat, lines = _filecache[filename]
190 if stat[ST_SIZE] = cached_stat[ST_SIZE] and \
191 stat[ST_MTIME] = cached_stat[ST_MTIME]:
192 cache_ok = 1
193 else:
194 print 'Stale cache entry for', filename
195 del _filecache[filename]
196 if not cache_ok:
197 lines = readfilelines(filename)
198 if not lines:
199 return ''
200 _filecache[filename] = stat, lines
201 if 0 <= lineno-1 < len(lines):
202 return lines[lineno-1]
203 else:
204 print 'Line number out of range, last line is', len(lines)
205 return ''
206
207def readfilelines(filename):
208 try:
209 fp = open(filename, 'r')
210 except:
211 print 'Cannot open', filename
212 return []
213 lines = []
214 while 1:
215 line = fp.readline()
216 if not line: break
217 lines.append(line)
218 if not lines:
219 print 'Empty file', filename
220 return lines