1364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro"""More comprehensive traceback formatting for Python scripts. 26b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 36b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping YeeTo enable this module, do: 46b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 56b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee import cgitb; cgitb.enable() 66b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 7364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaroat the top of your script. The optional arguments to enable() are: 86b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 96b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee display - if true, tracebacks are displayed in the web browser 106b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee logdir - if set, tracebacks are written to files in this directory 1183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee context - number of lines of source code to show for each stack frame 12478c10554b366989b341af4017602571edfe9b2eTim Peters format - 'text' or 'html' controls the output format 136b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 14364ca40c2a053718f67c2032769de1f1fd76bb22Skip MontanaroBy default, tracebacks are displayed but not saved, the context is 5 lines 15364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaroand the output format is 'html' (for backwards compatibility with the 16364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarooriginal use of this module) 176b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 186b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping YeeAlternatively, if you have caught an exception and want cgitb to display it 19364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarofor you, call cgitb.handler(). The optional argument to handler() is a 20364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro3-item tuple (etype, evalue, etb) just like the value of sys.exc_info(). 21364ca40c2a053718f67c2032769de1f1fd76bb22Skip MontanaroThe default handler displays output as HTML. 226b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 23ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannon""" 24ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport inspect 25ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport keyword 26ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport linecache 27ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport os 28ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport pydoc 29fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yeeimport sys 30ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport tempfile 31ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport time 32ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport tokenize 33ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport traceback 34ad078a0d7a4a4a840c259ec4a744043375de452bBrett Cannonimport types 35fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee 366b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yeedef reset(): 376b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee """Return a string that resets the CGI and browser to a known state.""" 386b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee return '''<!--: spam 396b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping YeeContent-Type: text/html 406b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 4183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> 4283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> --> 436b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee</font> </font> </font> </script> </object> </blockquote> </pre> 446b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee</table> </table> </table> </table> </table> </font> </font> </font>''' 456b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 4683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee__UNDEF__ = [] # a special sentinel object 475fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchlingdef small(text): 485fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling if text: 495fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling return '<small>' + text + '</small>' 505fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling else: 515fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling return '' 52182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 535fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchlingdef strong(text): 545fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling if text: 555fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling return '<strong>' + text + '</strong>' 565fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling else: 575fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling return '' 58182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 595fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchlingdef grey(text): 605fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling if text: 615fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling return '<font color="#909090">' + text + '</font>' 625fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling else: 635fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling return '' 6483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 6583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef lookup(name, frame, locals): 6683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Find the value for a given name in the given environment.""" 6783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if name in locals: 6883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee return 'local', locals[name] 6983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if name in frame.f_globals: 7083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee return 'global', frame.f_globals[name] 71711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if '__builtins__' in frame.f_globals: 72711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee builtins = frame.f_globals['__builtins__'] 73711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if type(builtins) is type({}): 74711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if name in builtins: 75711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee return 'builtin', builtins[name] 76711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee else: 77711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if hasattr(builtins, name): 78711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee return 'builtin', getattr(builtins, name) 7983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee return None, __UNDEF__ 8083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 8183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef scanvars(reader, frame, locals): 8283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Scan one logical line of Python and look up values of variables used.""" 8326f6bdf4f19336c125e3fac7aacaf55b312f474bAndrew M. Kuchling vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__ 8483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee for ttype, token, start, end, line in tokenize.generate_tokens(reader): 8583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if ttype == tokenize.NEWLINE: break 8683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if ttype == tokenize.NAME and token not in keyword.kwlist: 8783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if lasttoken == '.': 8883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if parent is not __UNDEF__: 8983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee value = getattr(parent, token, __UNDEF__) 9083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee vars.append((prefix + token, prefix, value)) 9183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 9283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee where, value = lookup(token, frame, locals) 9383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee vars.append((token, where, value)) 9483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee elif token == '.': 9583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee prefix += lasttoken + '.' 9683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee parent = value 9783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 9883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee parent, prefix = None, '' 9983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee lasttoken = token 10083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee return vars 10183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 1028d1da0f5c3b8c6e3fa29e6ae7f891f699a041bb6Florent Xiclunadef html(einfo, context=5): 10383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Return a nice HTML document describing a given traceback.""" 1048d1da0f5c3b8c6e3fa29e6ae7f891f699a041bb6Florent Xicluna etype, evalue, etb = einfo 1056b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if type(etype) is types.ClassType: 1066b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee etype = etype.__name__ 1076b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable 1086b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee date = time.ctime(time.time()) 10983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee head = '<body bgcolor="#f0f0f8">' + pydoc.html.heading( 1105fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling '<big><big>%s</big></big>' % 1115fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling strong(pydoc.html.escape(str(etype))), 11283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee '#ffffff', '#6622aa', pyver + '<br>' + date) + ''' 11383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<p>A problem occurred in a Python script. Here is the sequence of 1145fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchlingfunction calls leading up to the error, in the order they occurred.</p>''' 1156b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 11683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee indent = '<tt>' + small(' ' * 5) + ' </tt>' 1176b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee frames = [] 1186b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee records = inspect.getinnerframes(etb, context) 1196b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for frame, file, lnum, func, lines, index in records: 12007c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl if file: 12107c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl file = os.path.abspath(file) 12207c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl link = '<a href="file://%s">%s</a>' % (file, pydoc.html.escape(file)) 12307c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl else: 12407c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl file = link = '?' 1256b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee args, varargs, varkw, locals = inspect.getargvalues(frame) 12683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee call = '' 12783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if func != '?': 12883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee call = 'in ' + strong(func) + \ 12983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee inspect.formatargvalues(args, varargs, varkw, locals, 13083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee formatvalue=lambda value: '=' + pydoc.html.repr(value)) 13183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 13283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee highlight = {} 13383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee def reader(lnum=[lnum]): 13483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee highlight[lnum[0]] = 1 13583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee try: return linecache.getline(file, lnum[0]) 13683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee finally: lnum[0] += 1 13783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee vars = scanvars(reader, frame, locals) 13883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 13983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows = ['<tr><td bgcolor="#d8bbff">%s%s %s</td></tr>' % 14083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee ('<big> </big>', link, call)] 1416b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if index is not None: 1426b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee i = lnum - index 1436b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for line in lines: 14483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee num = small(' ' * (5-len(str(i))) + str(i)) + ' ' 14583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if i in highlight: 1467ab5eb91b7aba558ef39d7fa4ca7d3a63d4e886eGeorg Brandl line = '<tt>=>%s%s</tt>' % (num, pydoc.html.preformat(line)) 14783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td bgcolor="#ffccee">%s</td></tr>' % line) 14883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 1497ab5eb91b7aba558ef39d7fa4ca7d3a63d4e886eGeorg Brandl line = '<tt> %s%s</tt>' % (num, pydoc.html.preformat(line)) 15083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td>%s</td></tr>' % grey(line)) 15183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee i += 1 15283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 15383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee done, dump = {}, [] 15483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee for name, where, value in vars: 15583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if name in done: continue 15683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee done[name] = 1 15783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if value is not __UNDEF__: 158dbecd93b7203cd187c1978de1207c29d3a9a686cRaymond Hettinger if where in ('global', 'builtin'): 159711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = ('<em>%s</em> ' % where) + strong(name) 160711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee elif where == 'local': 161711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = strong(name) 162711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee else: 163711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = where + strong(name.split('.')[-1]) 16483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee dump.append('%s = %s' % (name, pydoc.html.repr(value))) 16583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 16683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee dump.append(name + ' <em>undefined</em>') 16783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 16883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td>%s</td></tr>' % small(grey(', '.join(dump)))) 1695fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling frames.append(''' 17083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<table width="100%%" cellspacing=0 cellpadding=0 border=0> 17183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee%s</table>''' % '\n'.join(rows)) 17283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 173b67c94318ec85722ce01c03955d6fbf50e3f7aa9Andrew M. Kuchling exception = ['<p>%s: %s' % (strong(pydoc.html.escape(str(etype))), 174b67c94318ec85722ce01c03955d6fbf50e3f7aa9Andrew M. Kuchling pydoc.html.escape(str(evalue)))] 175135c3174e7edbb2e01fabacfd5e015e49b640efdGeorg Brandl if isinstance(evalue, BaseException): 1766b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for name in dir(evalue): 177711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if name[:1] == '_': continue 1786b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee value = pydoc.html.repr(getattr(evalue, name)) 1796b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee exception.append('\n<br>%s%s =\n%s' % (indent, name, value)) 1806b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1816b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee return head + ''.join(frames) + ''.join(exception) + ''' 1826b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1836b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 18483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<!-- The above is a description of an error in a Python program, formatted 18583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee for a Web browser because the 'cgitb' module was enabled. In case you 18683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee are not reading this in a Web browser, here is the original traceback: 1876b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1886b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee%s 1896b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee--> 190a09a96a5440144f926c69250dab7b9bbf06bd789Georg Brandl''' % pydoc.html.escape( 191a09a96a5440144f926c69250dab7b9bbf06bd789Georg Brandl ''.join(traceback.format_exception(etype, evalue, etb))) 1926b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1938d1da0f5c3b8c6e3fa29e6ae7f891f699a041bb6Florent Xiclunadef text(einfo, context=5): 194364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro """Return a plain text document describing a given traceback.""" 1958d1da0f5c3b8c6e3fa29e6ae7f891f699a041bb6Florent Xicluna etype, evalue, etb = einfo 196364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if type(etype) is types.ClassType: 197364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro etype = etype.__name__ 198364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable 199364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro date = time.ctime(time.time()) 200364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro head = "%s\n%s\n%s\n" % (str(etype), pyver, date) + ''' 201364ca40c2a053718f67c2032769de1f1fd76bb22Skip MontanaroA problem occurred in a Python script. Here is the sequence of 202364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarofunction calls leading up to the error, in the order they occurred. 203364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro''' 204364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 205364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro frames = [] 206364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro records = inspect.getinnerframes(etb, context) 207364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for frame, file, lnum, func, lines, index in records: 208364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro file = file and os.path.abspath(file) or '?' 209364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro args, varargs, varkw, locals = inspect.getargvalues(frame) 210364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro call = '' 211364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if func != '?': 212364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro call = 'in ' + func + \ 213364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro inspect.formatargvalues(args, varargs, varkw, locals, 214364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro formatvalue=lambda value: '=' + pydoc.text.repr(value)) 215364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 216364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro highlight = {} 217364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro def reader(lnum=[lnum]): 218364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro highlight[lnum[0]] = 1 219364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro try: return linecache.getline(file, lnum[0]) 220364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro finally: lnum[0] += 1 221364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro vars = scanvars(reader, frame, locals) 222364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 223364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows = [' %s %s' % (file, call)] 224364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if index is not None: 225364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro i = lnum - index 226364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for line in lines: 227364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro num = '%5d ' % i 228364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows.append(num+line.rstrip()) 229364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro i += 1 230364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 231364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro done, dump = {}, [] 232364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for name, where, value in vars: 233364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if name in done: continue 234364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro done[name] = 1 235364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if value is not __UNDEF__: 236364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if where == 'global': name = 'global ' + name 2371c0228a51902233b3478e835be65198d305824e4Skip Montanaro elif where != 'local': name = where + name.split('.')[-1] 238364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro dump.append('%s = %s' % (name, pydoc.text.repr(value))) 239364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro else: 240364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro dump.append(name + ' undefined') 241364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 242364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows.append('\n'.join(dump)) 243364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro frames.append('\n%s\n' % '\n'.join(rows)) 244364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 245364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro exception = ['%s: %s' % (str(etype), str(evalue))] 246135c3174e7edbb2e01fabacfd5e015e49b640efdGeorg Brandl if isinstance(evalue, BaseException): 247364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for name in dir(evalue): 248364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro value = pydoc.text.repr(getattr(evalue, name)) 249364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro exception.append('\n%s%s = %s' % (" "*4, name, value)) 250364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 251364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro return head + ''.join(frames) + ''.join(exception) + ''' 252364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 253364ca40c2a053718f67c2032769de1f1fd76bb22Skip MontanaroThe above is a description of an error in a Python program. Here is 254364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarothe original traceback: 255364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 256364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro%s 257364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro''' % ''.join(traceback.format_exception(etype, evalue, etb)) 258364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 2596b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yeeclass Hook: 26083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """A hook to replace sys.excepthook that shows tracebacks in HTML.""" 26183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 262364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro def __init__(self, display=1, logdir=None, context=5, file=None, 263364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro format="html"): 2646b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.display = display # send tracebacks to browser if true 2656b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.logdir = logdir # log tracebacks to files if not None 26683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee self.context = context # number of source code lines per frame 267fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file = file or sys.stdout # place to send the output 268364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro self.format = format 2696b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2706b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee def __call__(self, etype, evalue, etb): 2716b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.handle((etype, evalue, etb)) 2726b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2736b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee def handle(self, info=None): 2746b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee info = info or sys.exc_info() 275364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if self.format == "html": 276364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro self.file.write(reset()) 2776b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 278364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro formatter = (self.format=="html") and html or text 279364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro plain = False 2806b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee try: 281364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro doc = formatter(info, self.context) 2826b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee except: # just in case something goes wrong 283364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro doc = ''.join(traceback.format_exception(*info)) 284364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro plain = True 2856b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2866b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if self.display: 287364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if plain: 2886b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee doc = doc.replace('&', '&').replace('<', '<') 289fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write('<pre>' + doc + '</pre>\n') 2906b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee else: 291fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write(doc + '\n') 2926b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee else: 293fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write('<p>A problem occurred in a Python script.\n') 2946b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2956b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if self.logdir is not None: 29630633c9a6423459cdd481a6e44954d5933c7842bAndrew M. Kuchling suffix = ['.txt', '.html'][self.format=="html"] 297364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir) 29854eed2e36d2c8e06ce1f1a30a3979587a3ac1af6R David Murray 2996b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee try: 3003b0a3293c369f3c3f4753e3cb9172cb4e242af76Guido van Rossum file = os.fdopen(fd, 'w') 3016b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee file.write(doc) 3026b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee file.close() 30354eed2e36d2c8e06ce1f1a30a3979587a3ac1af6R David Murray msg = '%s contains the description of this error.' % path 3046b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee except: 30554eed2e36d2c8e06ce1f1a30a3979587a3ac1af6R David Murray msg = 'Tried to save traceback to %s, but failed.' % path 30654eed2e36d2c8e06ce1f1a30a3979587a3ac1af6R David Murray 30754eed2e36d2c8e06ce1f1a30a3979587a3ac1af6R David Murray if self.format == 'html': 30854eed2e36d2c8e06ce1f1a30a3979587a3ac1af6R David Murray self.file.write('<p>%s</p>\n' % msg) 30954eed2e36d2c8e06ce1f1a30a3979587a3ac1af6R David Murray else: 31054eed2e36d2c8e06ce1f1a30a3979587a3ac1af6R David Murray self.file.write(msg + '\n') 311fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee try: 312fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.flush() 313fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee except: pass 3146b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 3156b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yeehandler = Hook().handle 316364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarodef enable(display=1, logdir=None, context=5, format="html"): 31783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Install an exception handler that formats tracebacks as HTML. 31883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 31983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee The optional argument 'display' can be set to 0 to suppress sending the 32083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee traceback to the browser, and 'logdir' can be set to a directory to cause 32183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee tracebacks to be written to files there.""" 322364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro sys.excepthook = Hook(display=display, logdir=logdir, 323364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro context=context, format=format) 324