cgitb.py revision 30633c9a6423459cdd481a6e44954d5933c7842b
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. 22364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro""" 236b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 246b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee__author__ = 'Ka-Ping Yee' 256b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee__version__ = '$Revision$' 266b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 27fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yeeimport sys 28fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee 296b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yeedef reset(): 306b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee """Return a string that resets the CGI and browser to a known state.""" 316b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee return '''<!--: spam 326b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping YeeContent-Type: text/html 336b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 3483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> 3583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> --> 366b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee</font> </font> </font> </script> </object> </blockquote> </pre> 376b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee</table> </table> </table> </table> </table> </font> </font> </font>''' 386b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 3983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee__UNDEF__ = [] # a special sentinel object 4083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef small(text): return '<small>' + text + '</small>' 4183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef strong(text): return '<strong>' + text + '</strong>' 4283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef grey(text): return '<font color="#909090">' + text + '</font>' 4383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 4483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef lookup(name, frame, locals): 4583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Find the value for a given name in the given environment.""" 4683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if name in locals: 4783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee return 'local', locals[name] 4883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if name in frame.f_globals: 4983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee return 'global', frame.f_globals[name] 50711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if '__builtins__' in frame.f_globals: 51711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee builtins = frame.f_globals['__builtins__'] 52711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if type(builtins) is type({}): 53711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if name in builtins: 54711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee return 'builtin', builtins[name] 55711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee else: 56711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if hasattr(builtins, name): 57711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee return 'builtin', getattr(builtins, name) 5883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee return None, __UNDEF__ 5983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 6083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef scanvars(reader, frame, locals): 6183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Scan one logical line of Python and look up values of variables used.""" 6283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee import tokenize, keyword 6383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee vars, lasttoken, parent, prefix = [], None, None, '' 6483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee for ttype, token, start, end, line in tokenize.generate_tokens(reader): 6583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if ttype == tokenize.NEWLINE: break 6683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if ttype == tokenize.NAME and token not in keyword.kwlist: 6783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if lasttoken == '.': 6883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if parent is not __UNDEF__: 6983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee value = getattr(parent, token, __UNDEF__) 7083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee vars.append((prefix + token, prefix, value)) 7183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 7283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee where, value = lookup(token, frame, locals) 7383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee vars.append((token, where, value)) 7483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee elif token == '.': 7583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee prefix += lasttoken + '.' 7683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee parent = value 7783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 7883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee parent, prefix = None, '' 7983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee lasttoken = token 8083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee return vars 8183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 8283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeedef html((etype, evalue, etb), context=5): 8383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Return a nice HTML document describing a given traceback.""" 84fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee import os, types, time, traceback, linecache, inspect, pydoc 856b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 866b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if type(etype) is types.ClassType: 876b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee etype = etype.__name__ 886b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable 896b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee date = time.ctime(time.time()) 9083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee head = '<body bgcolor="#f0f0f8">' + pydoc.html.heading( 916b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee '<big><big><strong>%s</strong></big></big>' % str(etype), 9283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee '#ffffff', '#6622aa', pyver + '<br>' + date) + ''' 9383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<p>A problem occurred in a Python script. Here is the sequence of 9483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yeefunction calls leading up to the error, in the order they occurred.''' 956b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 9683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee indent = '<tt>' + small(' ' * 5) + ' </tt>' 976b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee frames = [] 986b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee records = inspect.getinnerframes(etb, context) 996b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for frame, file, lnum, func, lines, index in records: 1006b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee file = file and os.path.abspath(file) or '?' 10183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee link = '<a href="file://%s">%s</a>' % (file, pydoc.html.escape(file)) 1026b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee args, varargs, varkw, locals = inspect.getargvalues(frame) 10383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee call = '' 10483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if func != '?': 10583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee call = 'in ' + strong(func) + \ 10683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee inspect.formatargvalues(args, varargs, varkw, locals, 10783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee formatvalue=lambda value: '=' + pydoc.html.repr(value)) 10883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 10983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee highlight = {} 11083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee def reader(lnum=[lnum]): 11183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee highlight[lnum[0]] = 1 11283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee try: return linecache.getline(file, lnum[0]) 11383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee finally: lnum[0] += 1 11483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee vars = scanvars(reader, frame, locals) 11583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 11683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows = ['<tr><td bgcolor="#d8bbff">%s%s %s</td></tr>' % 11783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee ('<big> </big>', link, call)] 1186b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if index is not None: 1196b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee i = lnum - index 1206b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for line in lines: 12183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee num = small(' ' * (5-len(str(i))) + str(i)) + ' ' 12283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee line = '<tt>%s%s</tt>' % (num, pydoc.html.preformat(line)) 12383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if i in highlight: 12483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td bgcolor="#ffccee">%s</td></tr>' % line) 12583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 12683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td>%s</td></tr>' % grey(line)) 12783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee i += 1 12883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 12983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee done, dump = {}, [] 13083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee for name, where, value in vars: 13183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if name in done: continue 13283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee done[name] = 1 13383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee if value is not __UNDEF__: 134711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if where in ['global', 'builtin']: 135711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = ('<em>%s</em> ' % where) + strong(name) 136711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee elif where == 'local': 137711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = strong(name) 138711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee else: 139711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee name = where + strong(name.split('.')[-1]) 14083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee dump.append('%s = %s' % (name, pydoc.html.repr(value))) 14183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee else: 14283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee dump.append(name + ' <em>undefined</em>') 14383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 14483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee rows.append('<tr><td>%s</td></tr>' % small(grey(', '.join(dump)))) 14583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee frames.append('''<p> 14683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<table width="100%%" cellspacing=0 cellpadding=0 border=0> 14783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee%s</table>''' % '\n'.join(rows)) 14883205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 149b67c94318ec85722ce01c03955d6fbf50e3f7aa9Andrew M. Kuchling exception = ['<p>%s: %s' % (strong(pydoc.html.escape(str(etype))), 150b67c94318ec85722ce01c03955d6fbf50e3f7aa9Andrew M. Kuchling pydoc.html.escape(str(evalue)))] 1516b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if type(evalue) is types.InstanceType: 1526b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee for name in dir(evalue): 153711cad769a60b4a53520bb1daf580d2ca252b450Ka-Ping Yee if name[:1] == '_': continue 1546b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee value = pydoc.html.repr(getattr(evalue, name)) 1556b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee exception.append('\n<br>%s%s =\n%s' % (indent, name, value)) 1566b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1576b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee import traceback 1586b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee return head + ''.join(frames) + ''.join(exception) + ''' 1596b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1606b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 16183205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee<!-- The above is a description of an error in a Python program, formatted 16283205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee for a Web browser because the 'cgitb' module was enabled. In case you 16383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee are not reading this in a Web browser, here is the original traceback: 1646b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 1656b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee%s 1666b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee--> 16783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee''' % ''.join(traceback.format_exception(etype, evalue, etb)) 1686b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 169364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarodef text((etype, evalue, etb), context=5): 170364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro """Return a plain text document describing a given traceback.""" 171364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro import os, types, time, traceback, linecache, inspect, pydoc 172364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 173364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if type(etype) is types.ClassType: 174364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro etype = etype.__name__ 175364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable 176364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro date = time.ctime(time.time()) 177364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro head = "%s\n%s\n%s\n" % (str(etype), pyver, date) + ''' 178364ca40c2a053718f67c2032769de1f1fd76bb22Skip MontanaroA problem occurred in a Python script. Here is the sequence of 179364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarofunction calls leading up to the error, in the order they occurred. 180364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro''' 181364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 182364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro frames = [] 183364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro records = inspect.getinnerframes(etb, context) 184364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for frame, file, lnum, func, lines, index in records: 185364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro file = file and os.path.abspath(file) or '?' 186364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro args, varargs, varkw, locals = inspect.getargvalues(frame) 187364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro call = '' 188364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if func != '?': 189364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro call = 'in ' + func + \ 190364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro inspect.formatargvalues(args, varargs, varkw, locals, 191364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro formatvalue=lambda value: '=' + pydoc.text.repr(value)) 192364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 193364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro highlight = {} 194364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro def reader(lnum=[lnum]): 195364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro highlight[lnum[0]] = 1 196364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro try: return linecache.getline(file, lnum[0]) 197364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro finally: lnum[0] += 1 198364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro vars = scanvars(reader, frame, locals) 199364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 200364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows = [' %s %s' % (file, call)] 201364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if index is not None: 202364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro i = lnum - index 203364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for line in lines: 204364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro num = '%5d ' % i 205364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows.append(num+line.rstrip()) 206364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro i += 1 207364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 208364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro done, dump = {}, [] 209364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for name, where, value in vars: 210364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if name in done: continue 211364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro done[name] = 1 212364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if value is not __UNDEF__: 213364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if where == 'global': name = 'global ' + name 214364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro elif where == 'local': name = name 215364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro else: name = where + name.split('.')[-1] 216364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro dump.append('%s = %s' % (name, pydoc.text.repr(value))) 217364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro else: 218364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro dump.append(name + ' undefined') 219364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 220364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro rows.append('\n'.join(dump)) 221364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro frames.append('\n%s\n' % '\n'.join(rows)) 222364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 223364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro exception = ['%s: %s' % (str(etype), str(evalue))] 224364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if type(evalue) is types.InstanceType: 225364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro for name in dir(evalue): 226364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro value = pydoc.text.repr(getattr(evalue, name)) 227364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro exception.append('\n%s%s = %s' % (" "*4, name, value)) 228364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 229364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro import traceback 230364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro return head + ''.join(frames) + ''.join(exception) + ''' 231364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 232364ca40c2a053718f67c2032769de1f1fd76bb22Skip MontanaroThe above is a description of an error in a Python program. Here is 233364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarothe original traceback: 234364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 235364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro%s 236364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro''' % ''.join(traceback.format_exception(etype, evalue, etb)) 237364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro 2386b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yeeclass Hook: 23983205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """A hook to replace sys.excepthook that shows tracebacks in HTML.""" 24083205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 241364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro def __init__(self, display=1, logdir=None, context=5, file=None, 242364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro format="html"): 2436b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.display = display # send tracebacks to browser if true 2446b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.logdir = logdir # log tracebacks to files if not None 24583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee self.context = context # number of source code lines per frame 246fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file = file or sys.stdout # place to send the output 247364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro self.format = format 2486b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2496b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee def __call__(self, etype, evalue, etb): 2506b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee self.handle((etype, evalue, etb)) 2516b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2526b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee def handle(self, info=None): 2536b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee info = info or sys.exc_info() 254364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if self.format == "html": 255364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro self.file.write(reset()) 2566b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 257364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro formatter = (self.format=="html") and html or text 258364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro plain = False 2596b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee try: 260364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro doc = formatter(info, self.context) 2616b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee except: # just in case something goes wrong 2626b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee import traceback 263364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro doc = ''.join(traceback.format_exception(*info)) 264364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro plain = True 2656b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2666b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if self.display: 267364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro if plain: 2686b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee doc = doc.replace('&', '&').replace('<', '<') 269fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write('<pre>' + doc + '</pre>\n') 2706b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee else: 271fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write(doc + '\n') 2726b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee else: 273fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write('<p>A problem occurred in a Python script.\n') 2746b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2756b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee if self.logdir is not None: 27683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee import os, tempfile 27730633c9a6423459cdd481a6e44954d5933c7842bAndrew M. Kuchling suffix = ['.txt', '.html'][self.format=="html"] 278364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir) 2796b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee try: 2803b0a3293c369f3c3f4753e3cb9172cb4e242af76Guido van Rossum file = os.fdopen(fd, 'w') 2816b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee file.write(doc) 2826b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee file.close() 283fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee msg = '<p> %s contains the description of this error.' % path 2846b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee except: 285fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee msg = '<p> Tried to save traceback to %s, but failed.' % path 286fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.write(msg + '\n') 287fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee try: 288fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee self.file.flush() 289fa78d0fbe45a7f16d5d30c3d4e3ad30dc4933e8fKa-Ping Yee except: pass 2906b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yee 2916b5a48d48ea15c1364b2fbc8552f50ebf72fa64aKa-Ping Yeehandler = Hook().handle 292364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanarodef enable(display=1, logdir=None, context=5, format="html"): 29383205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee """Install an exception handler that formats tracebacks as HTML. 29483205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee 29583205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee The optional argument 'display' can be set to 0 to suppress sending the 29683205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee traceback to the browser, and 'logdir' can be set to a directory to cause 29783205972a2d027517ebedd827d1c19a5b0264c0aKa-Ping Yee tracebacks to be written to files there.""" 298364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro sys.excepthook = Hook(display=display, logdir=logdir, 299364ca40c2a053718f67c2032769de1f1fd76bb22Skip Montanaro context=context, format=format) 300