0001 """More comprehensive traceback formatting for Python scripts. 0002 0003 To enable this module, do: 0004 0005 import cgitb; cgitb.enable() 0006 0007 at the top of your script. The optional arguments to enable() are: 0008 0009 display - if true, tracebacks are displayed in the web browser 0010 logdir - if set, tracebacks are written to files in this directory 0011 context - number of lines of source code to show for each stack frame 0012 format - 'text' or 'html' controls the output format 0013 0014 By default, tracebacks are displayed but not saved, the context is 5 lines 0015 and the output format is 'html' (for backwards compatibility with the 0016 original use of this module) 0017 0018 Alternatively, if you have caught an exception and want cgitb to display it 0019 for you, call cgitb.handler(). The optional argument to handler() is a 0020 3-item tuple (etype, evalue, etb) just like the value of sys.exc_info(). 0021 The default handler displays output as HTML. 0022 """ 0023 0024 __author__ = 'Ka-Ping Yee' 0025 __version__ = '$Revision: 1.15 $' 0026 0027 import sys 0028 0029 def reset(): 0030 """Return a string that resets the CGI and browser to a known state.""" 0031 return '''<!--: spam 0032 Content-Type: text/html 0033 0034 <body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> 0035 <body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> --> 0036 </font> </font> </font> </script> </object> </blockquote> </pre> 0037 </table> </table> </table> </table> </table> </font> </font> </font>''' 0038 0039 __UNDEF__ = [] # a special sentinel object 0040 def small(text): 0041 if text: 0042 return '<small>' + text + '</small>' 0043 else: 0044 return '' 0045 0046 def strong(text): 0047 if text: 0048 return '<strong>' + text + '</strong>' 0049 else: 0050 return '' 0051 0052 def grey(text): 0053 if text: 0054 return '<font color="#909090">' + text + '</font>' 0055 else: 0056 return '' 0057 0058 def lookup(name, frame, locals): 0059 """Find the value for a given name in the given environment.""" 0060 if name in locals: 0061 return 'local', locals[name] 0062 if name in frame.f_globals: 0063 return 'global', frame.f_globals[name] 0064 if '__builtins__' in frame.f_globals: 0065 builtins = frame.f_globals['__builtins__'] 0066 if type(builtins) is type({}): 0067 if name in builtins: 0068 return 'builtin', builtins[name] 0069 else: 0070 if hasattr(builtins, name): 0071 return 'builtin', getattr(builtins, name) 0072 return None, __UNDEF__ 0073 0074 def scanvars(reader, frame, locals): 0075 """Scan one logical line of Python and look up values of variables used.""" 0076 import tokenize, keyword 0077 vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__ 0078 for ttype, token, start, end, line in tokenize.generate_tokens(reader): 0079 if ttype == tokenize.NEWLINE: break 0080 if ttype == tokenize.NAME and token not in keyword.kwlist: 0081 if lasttoken == '.': 0082 if parent is not __UNDEF__: 0083 value = getattr(parent, token, __UNDEF__) 0084 vars.append((prefix + token, prefix, value)) 0085 else: 0086 where, value = lookup(token, frame, locals) 0087 vars.append((token, where, value)) 0088 elif token == '.': 0089 prefix += lasttoken + '.' 0090 parent = value 0091 else: 0092 parent, prefix = None, '' 0093 lasttoken = token 0094 return vars 0095 0096 def html((etype, evalue, etb), context=5): 0097 """Return a nice HTML document describing a given traceback.""" 0098 import os, types, time, traceback, linecache, inspect, pydoc 0099 0100 if type(etype) is types.ClassType: 0101 etype = etype.__name__ 0102 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable 0103 date = time.ctime(time.time()) 0104 head = '<body bgcolor="#f0f0f8">' + pydoc.html.heading( 0105 '<big><big>%s</big></big>' % 0106 strong(pydoc.html.escape(str(etype))), 0107 '#ffffff', '#6622aa', pyver + '<br>' + date) + ''' 0108 <p>A problem occurred in a Python script. Here is the sequence of 0109 function calls leading up to the error, in the order they occurred.</p>''' 0110 0111 indent = '<tt>' + small(' ' * 5) + ' </tt>' 0112 frames = [] 0113 records = inspect.getinnerframes(etb, context) 0114 for frame, file, lnum, func, lines, index in records: 0115 file = file and os.path.abspath(file) or '?' 0116 link = '<a href="file://%s">%s</a>' % (file, pydoc.html.escape(file)) 0117 args, varargs, varkw, locals = inspect.getargvalues(frame) 0118 call = '' 0119 if func != '?': 0120 call = 'in ' + strong(func) + \ 0121 inspect.formatargvalues(args, varargs, varkw, locals, 0122 formatvalue=lambda value: '=' + pydoc.html.repr(value)) 0123 0124 highlight = {} 0125 def reader(lnum=[lnum]): 0126 highlight[lnum[0]] = 1 0127 try: return linecache.getline(file, lnum[0]) 0128 finally: lnum[0] += 1 0129 vars = scanvars(reader, frame, locals) 0130 0131 rows = ['<tr><td bgcolor="#d8bbff">%s%s %s</td></tr>' % 0132 ('<big> </big>', link, call)] 0133 if index is not None: 0134 i = lnum - index 0135 for line in lines: 0136 num = small(' ' * (5-len(str(i))) + str(i)) + ' ' 0137 line = '<tt>%s%s</tt>' % (num, pydoc.html.preformat(line)) 0138 if i in highlight: 0139 rows.append('<tr><td bgcolor="#ffccee">%s</td></tr>' % line) 0140 else: 0141 rows.append('<tr><td>%s</td></tr>' % grey(line)) 0142 i += 1 0143 0144 done, dump = {}, [] 0145 for name, where, value in vars: 0146 if name in done: continue 0147 done[name] = 1 0148 if value is not __UNDEF__: 0149 if where in ['global', 'builtin']: 0150 name = ('<em>%s</em> ' % where) + strong(name) 0151 elif where == 'local': 0152 name = strong(name) 0153 else: 0154 name = where + strong(name.split('.')[-1]) 0155 dump.append('%s = %s' % (name, pydoc.html.repr(value))) 0156 else: 0157 dump.append(name + ' <em>undefined</em>') 0158 0159 rows.append('<tr><td>%s</td></tr>' % small(grey(', '.join(dump)))) 0160 frames.append(''' 0161 <table width="100%%" cellspacing=0 cellpadding=0 border=0> 0162 %s</table>''' % '\n'.join(rows)) 0163 0164 exception = ['<p>%s: %s' % (strong(pydoc.html.escape(str(etype))), 0165 pydoc.html.escape(str(evalue)))] 0166 if type(evalue) is types.InstanceType: 0167 for name in dir(evalue): 0168 if name[:1] == '_': continue 0169 value = pydoc.html.repr(getattr(evalue, name)) 0170 exception.append('\n<br>%s%s =\n%s' % (indent, name, value)) 0171 0172 import traceback 0173 return head + ''.join(frames) + ''.join(exception) + ''' 0174 0175 0176 <!-- The above is a description of an error in a Python program, formatted 0177 for a Web browser because the 'cgitb' module was enabled. In case you 0178 are not reading this in a Web browser, here is the original traceback: 0179 0180 %s 0181 --> 0182 ''' % ''.join(traceback.format_exception(etype, evalue, etb)) 0183 0184 def text((etype, evalue, etb), context=5): 0185 """Return a plain text document describing a given traceback.""" 0186 import os, types, time, traceback, linecache, inspect, pydoc 0187 0188 if type(etype) is types.ClassType: 0189 etype = etype.__name__ 0190 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable 0191 date = time.ctime(time.time()) 0192 head = "%s\n%s\n%s\n" % (str(etype), pyver, date) + ''' 0193 A problem occurred in a Python script. Here is the sequence of 0194 function calls leading up to the error, in the order they occurred. 0195 ''' 0196 0197 frames = [] 0198 records = inspect.getinnerframes(etb, context) 0199 for frame, file, lnum, func, lines, index in records: 0200 file = file and os.path.abspath(file) or '?' 0201 args, varargs, varkw, locals = inspect.getargvalues(frame) 0202 call = '' 0203 if func != '?': 0204 call = 'in ' + func + \ 0205 inspect.formatargvalues(args, varargs, varkw, locals, 0206 formatvalue=lambda value: '=' + pydoc.text.repr(value)) 0207 0208 highlight = {} 0209 def reader(lnum=[lnum]): 0210 highlight[lnum[0]] = 1 0211 try: return linecache.getline(file, lnum[0]) 0212 finally: lnum[0] += 1 0213 vars = scanvars(reader, frame, locals) 0214 0215 rows = [' %s %s' % (file, call)] 0216 if index is not None: 0217 i = lnum - index 0218 for line in lines: 0219 num = '%5d ' % i 0220 rows.append(num+line.rstrip()) 0221 i += 1 0222 0223 done, dump = {}, [] 0224 for name, where, value in vars: 0225 if name in done: continue 0226 done[name] = 1 0227 if value is not __UNDEF__: 0228 if where == 'global': name = 'global ' + name 0229 elif where != 'local': name = where + name.split('.')[-1] 0230 dump.append('%s = %s' % (name, pydoc.text.repr(value))) 0231 else: 0232 dump.append(name + ' undefined') 0233 0234 rows.append('\n'.join(dump)) 0235 frames.append('\n%s\n' % '\n'.join(rows)) 0236 0237 exception = ['%s: %s' % (str(etype), str(evalue))] 0238 if type(evalue) is types.InstanceType: 0239 for name in dir(evalue): 0240 value = pydoc.text.repr(getattr(evalue, name)) 0241 exception.append('\n%s%s = %s' % (" "*4, name, value)) 0242 0243 import traceback 0244 return head + ''.join(frames) + ''.join(exception) + ''' 0245 0246 The above is a description of an error in a Python program. Here is 0247 the original traceback: 0248 0249 %s 0250 ''' % ''.join(traceback.format_exception(etype, evalue, etb)) 0251 0252 class Hook: 0253 """A hook to replace sys.excepthook that shows tracebacks in HTML.""" 0254 0255 def __init__(self, display=1, logdir=None, context=5, file=None, 0256 format="html"): 0257 self.display = display # send tracebacks to browser if true 0258 self.logdir = logdir # log tracebacks to files if not None 0259 self.context = context # number of source code lines per frame 0260 self.file = file or sys.stdout # place to send the output 0261 self.format = format 0262 0263 def __call__(self, etype, evalue, etb): 0264 self.handle((etype, evalue, etb)) 0265 0266 def handle(self, info=None): 0267 info = info or sys.exc_info() 0268 if self.format == "html": 0269 self.file.write(reset()) 0270 0271 formatter = (self.format=="html") and html or text 0272 plain = False 0273 try: 0274 doc = formatter(info, self.context) 0275 except: # just in case something goes wrong 0276 import traceback 0277 doc = ''.join(traceback.format_exception(*info)) 0278 plain = True 0279 0280 if self.display: 0281 if plain: 0282 doc = doc.replace('&', '&').replace('<', '<') 0283 self.file.write('<pre>' + doc + '</pre>\n') 0284 else: 0285 self.file.write(doc + '\n') 0286 else: 0287 self.file.write('<p>A problem occurred in a Python script.\n') 0288 0289 if self.logdir is not None: 0290 import os, tempfile 0291 suffix = ['.txt', '.html'][self.format=="html"] 0292 (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir) 0293 try: 0294 file = os.fdopen(fd, 'w') 0295 file.write(doc) 0296 file.close() 0297 msg = '<p> %s contains the description of this error.' % path 0298 except: 0299 msg = '<p> Tried to save traceback to %s, but failed.' % path 0300 self.file.write(msg + '\n') 0301 try: 0302 self.file.flush() 0303 except: pass 0304 0305 handler = Hook().handle 0306 def enable(display=1, logdir=None, context=5, format="html"): 0307 """Install an exception handler that formats tracebacks as HTML. 0308 0309 The optional argument 'display' can be set to 0 to suppress sending the 0310 traceback to the browser, and 'logdir' can be set to a directory to cause 0311 tracebacks to be written to files there.""" 0312 sys.excepthook = Hook(display=display, logdir=logdir, 0313 context=context, format=format) 0314
Generated by PyXR 0.9.4