cgitb.py revision ad078a0d7a4a4a840c259ec4a744043375de452b
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 10283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef html((etype, evalue, etb), context=5): 10383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Return a nice HTML document describing a given traceback.""" 1046b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if type(etype) is types.ClassType: 1056b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee etype = etype.__name__ 1066b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable 1076b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee date = time.ctime(time.time()) 10883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee head = '<body bgcolor="#f0f0f8">' + pydoc.html.heading( 1095fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling '<big><big>%s</big></big>' % 1105fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling strong(pydoc.html.escape(str(etype))), 11183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee '#ffffff', '#6622aa', pyver + '<br>' + date) + ''' 11283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<p>A problem occurred in a Python script. Here is the sequence of 1135fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchlingfunction calls leading up to the error, in the order they occurred.</p>''' 1146b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 11583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee indent = '<tt>' + small(' ' * 5) + ' </tt>' 1166b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee frames = [] 1176b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee records = inspect.getinnerframes(etb, context) 1186b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for frame, file, lnum, func, lines, index in records: 11907c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl if file: 12007c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl file = os.path.abspath(file) 12107c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl link = '<a href="file://%s">%s</a>' % (file, pydoc.html.escape(file)) 12207c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl else: 12307c81d9074fd72cb6a7ad1548685a87d5a764a09Georg Brandl file = link = '?' 1246b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee args, varargs, varkw, locals = inspect.getargvalues(frame) 12583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee call = '' 12683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if func != '?': 12783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee call = 'in ' + strong(func) + \ 12883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee inspect.formatargvalues(args, varargs, varkw, locals, 12983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee formatvalue=lambda value: '=' + pydoc.html.repr(value)) 13083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 13183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee highlight = {} 13283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee def reader(lnum=[lnum]): 13383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee highlight[lnum[0]] = 1 13483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee try: return linecache.getline(file, lnum[0]) 13583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee finally: lnum[0] += 1 13683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee vars = scanvars(reader, frame, locals) 13783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 13883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows = ['<tr><td bgcolor="#d8bbff">%s%s %s</td></tr>' % 13983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee ('<big> </big>', link, call)] 1406b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if index is not None: 1416b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee i = lnum - index 1426b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for line in lines: 14383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee num = small(' ' * (5-len(str(i))) + str(i)) + ' ' 14483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee line = '<tt>%s%s</tt>' % (num, pydoc.html.preformat(line)) 14583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if i in highlight: 14683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td bgcolor="#ffccee">%s</td></tr>' % line) 14783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 14883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td>%s</td></tr>' % grey(line)) 14983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee i += 1 15083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 15183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee done, dump = {}, [] 15283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee for name, where, value in vars: 15383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if name in done: continue 15483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee done[name] = 1 15583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if value is not __UNDEF__: 156dbecd93b7203cd187c1978de1207c29d3a9a686cRaymond Hettinger if where in ('global', 'builtin'): 157711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = ('<em>%s</em> ' % where) + strong(name) 158711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee elif where == 'local': 159711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = strong(name) 160711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee else: 161711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = where + strong(name.split('.')[-1]) 16283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee dump.append('%s = %s' % (name, pydoc.html.repr(value))) 16383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 16483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee dump.append(name + ' <em>undefined</em>') 16583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 16683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td>%s</td></tr>' % small(grey(', '.join(dump)))) 1675fcefdb32600fa64d3160f031d48fb033150fdb3Andrew M. Kuchling frames.append(''' 16883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<table width="100%%" cellspacing=0 cellpadding=0 border=0> 16983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee%s</table>''' % '\n'.join(rows)) 17083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 171b67c94318ec85722ce01c03955d6fbf50e3f7aa9Andrew M. Kuchling exception = ['<p>%s: %s' % (strong(pydoc.html.escape(str(etype))), 172b67c94318ec85722ce01c03955d6fbf50e3f7aa9Andrew M. Kuchling pydoc.html.escape(str(evalue)))] 173135c3174e7edbb2e01fabacfd5e015e49b640efdGeorg Brandl if isinstance(evalue, BaseException): 1746b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for name in dir(evalue): 175711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if name[:1] == '_': continue 1766b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee value = pydoc.html.repr(getattr(evalue, name)) 1776b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee exception.append('\n<br>%s%s =\n%s' % (indent, name, value)) 1786b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1796b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee return head + ''.join(frames) + ''.join(exception) + ''' 1806b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1816b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 18283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<!-- The above is a description of an error in a Python program, formatted 18383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee for a Web browser because the 'cgitb' module was enabled. In case you 18483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee are not reading this in a Web browser, here is the original traceback: 1856b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1866b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee%s 1876b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee--> 188a09a96a5440144f926c69250dab7b9bbf06bd789Georg Brandl''' % pydoc.html.escape( 189a09a96a5440144f926c69250dab7b9bbf06bd789Georg Brandl ''.join(traceback.format_exception(etype, evalue, etb))) 1906b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 191364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarodef text((etype, evalue, etb), context=5): 192364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro """Return a plain text document describing a given traceback.""" 193364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if type(etype) is types.ClassType: 194364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro etype = etype.__name__ 195364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable 196364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro date = time.ctime(time.time()) 197364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro head = "%s\n%s\n%s\n" % (str(etype), pyver, date) + ''' 198364ca40c2a053718f67c2032769de1f1fd76bb22Skip MontanaroA problem occurred in a Python script. Here is the sequence of 199364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarofunction calls leading up to the error, in the order they occurred. 200364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro''' 201364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 202364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro frames = [] 203364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro records = inspect.getinnerframes(etb, context) 204364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for frame, file, lnum, func, lines, index in records: 205364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro file = file and os.path.abspath(file) or '?' 206364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro args, varargs, varkw, locals = inspect.getargvalues(frame) 207364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro call = '' 208364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if func != '?': 209364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro call = 'in ' + func + \ 210364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro inspect.formatargvalues(args, varargs, varkw, locals, 211364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro formatvalue=lambda value: '=' + pydoc.text.repr(value)) 212364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 213364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro highlight = {} 214364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro def reader(lnum=[lnum]): 215364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro highlight[lnum[0]] = 1 216364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro try: return linecache.getline(file, lnum[0]) 217364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro finally: lnum[0] += 1 218364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro vars = scanvars(reader, frame, locals) 219364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 220364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows = [' %s %s' % (file, call)] 221364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if index is not None: 222364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro i = lnum - index 223364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for line in lines: 224364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro num = '%5d ' % i 225364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows.append(num+line.rstrip()) 226364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro i += 1 227364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 228364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro done, dump = {}, [] 229364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for name, where, value in vars: 230364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if name in done: continue 231364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro done[name] = 1 232364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if value is not __UNDEF__: 233364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if where == 'global': name = 'global ' + name 2341c0228a51902233b3478e835be65198d305824e4Skip Montanaro elif where != 'local': name = where + name.split('.')[-1] 235364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro dump.append('%s = %s' % (name, pydoc.text.repr(value))) 236364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro else: 237364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro dump.append(name + ' undefined') 238364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 239364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows.append('\n'.join(dump)) 240364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro frames.append('\n%s\n' % '\n'.join(rows)) 241364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 242364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro exception = ['%s: %s' % (str(etype), str(evalue))] 243135c3174e7edbb2e01fabacfd5e015e49b640efdGeorg Brandl if isinstance(evalue, BaseException): 244364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for name in dir(evalue): 245364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro value = pydoc.text.repr(getattr(evalue, name)) 246364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro exception.append('\n%s%s = %s' % (" "*4, name, value)) 247364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 248364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro return head + ''.join(frames) + ''.join(exception) + ''' 249364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 250364ca40c2a053718f67c2032769de1f1fd76bb22Skip MontanaroThe above is a description of an error in a Python program. Here is 251364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarothe original traceback: 252364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 253364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro%s 254364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro''' % ''.join(traceback.format_exception(etype, evalue, etb)) 255364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 2566b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yeeclass Hook: 25783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """A hook to replace sys.excepthook that shows tracebacks in HTML.""" 25883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 259364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro def __init__(self, display=1, logdir=None, context=5, file=None, 260364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro format="html"): 2616b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.display = display # send tracebacks to browser if true 2626b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.logdir = logdir # log tracebacks to files if not None 26383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee self.context = context # number of source code lines per frame 264fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file = file or sys.stdout # place to send the output 265364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro self.format = format 2666b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2676b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee def __call__(self, etype, evalue, etb): 2686b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.handle((etype, evalue, etb)) 2696b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2706b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee def handle(self, info=None): 2716b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee info = info or sys.exc_info() 272364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if self.format == "html": 273364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro self.file.write(reset()) 2746b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 275364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro formatter = (self.format=="html") and html or text 276364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro plain = False 2776b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee try: 278364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro doc = formatter(info, self.context) 2796b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee except: # just in case something goes wrong 280364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro doc = ''.join(traceback.format_exception(*info)) 281364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro plain = True 2826b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2836b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if self.display: 284364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if plain: 2856b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee doc = doc.replace('&', '&').replace('<', '<') 286fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write('<pre>' + doc + '</pre>\n') 2876b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee else: 288fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write(doc + '\n') 2896b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee else: 290fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write('<p>A problem occurred in a Python script.\n') 2916b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2926b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if self.logdir is not None: 29330633c9a6423459cdd481a6e44954d5933c7842bAndrew M. Kuchling suffix = ['.txt', '.html'][self.format=="html"] 294364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir) 2956b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee try: 2963b0a3293c369f3c3f4753e3cb9172cb4e242af76Guido van Rossum file = os.fdopen(fd, 'w') 2976b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee file.write(doc) 2986b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee file.close() 299fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee msg = '<p> %s contains the description of this error.' % path 3006b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee except: 301fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee msg = '<p> Tried to save traceback to %s, but failed.' % path 302fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write(msg + '\n') 303fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee try: 304fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.flush() 305fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee except: pass 3066b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 3076b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yeehandler = Hook().handle 308364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarodef enable(display=1, logdir=None, context=5, format="html"): 30983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Install an exception handler that formats tracebacks as HTML. 31083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 31183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee The optional argument 'display' can be set to 0 to suppress sending the 31283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee traceback to the browser, and 'logdir' can be set to a directory to cause 31383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee tracebacks to be written to files there.""" 314364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro sys.excepthook = Hook(display=display, logdir=logdir, 315364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro context=context, format=format) 316