+++ /dev/null
-"""More comprehensive traceback formatting for Python scripts.\r
-\r
-To enable this module, do:\r
-\r
- import cgitb; cgitb.enable()\r
-\r
-at the top of your script. The optional arguments to enable() are:\r
-\r
- display - if true, tracebacks are displayed in the web browser\r
- logdir - if set, tracebacks are written to files in this directory\r
- context - number of lines of source code to show for each stack frame\r
- format - 'text' or 'html' controls the output format\r
-\r
-By default, tracebacks are displayed but not saved, the context is 5 lines\r
-and the output format is 'html' (for backwards compatibility with the\r
-original use of this module)\r
-\r
-Alternatively, if you have caught an exception and want cgitb to display it\r
-for you, call cgitb.handler(). The optional argument to handler() is a\r
-3-item tuple (etype, evalue, etb) just like the value of sys.exc_info().\r
-The default handler displays output as HTML.\r
-\r
-"""\r
-import inspect\r
-import keyword\r
-import linecache\r
-import os\r
-import pydoc\r
-import sys\r
-import tempfile\r
-import time\r
-import tokenize\r
-import traceback\r
-import types\r
-\r
-def reset():\r
- """Return a string that resets the CGI and browser to a known state."""\r
- return '''<!--: spam\r
-Content-Type: text/html\r
-\r
-<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> -->\r
-<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> -->\r
-</font> </font> </font> </script> </object> </blockquote> </pre>\r
-</table> </table> </table> </table> </table> </font> </font> </font>'''\r
-\r
-__UNDEF__ = [] # a special sentinel object\r
-def small(text):\r
- if text:\r
- return '<small>' + text + '</small>'\r
- else:\r
- return ''\r
-\r
-def strong(text):\r
- if text:\r
- return '<strong>' + text + '</strong>'\r
- else:\r
- return ''\r
-\r
-def grey(text):\r
- if text:\r
- return '<font color="#909090">' + text + '</font>'\r
- else:\r
- return ''\r
-\r
-def lookup(name, frame, locals):\r
- """Find the value for a given name in the given environment."""\r
- if name in locals:\r
- return 'local', locals[name]\r
- if name in frame.f_globals:\r
- return 'global', frame.f_globals[name]\r
- if '__builtins__' in frame.f_globals:\r
- builtins = frame.f_globals['__builtins__']\r
- if type(builtins) is type({}):\r
- if name in builtins:\r
- return 'builtin', builtins[name]\r
- else:\r
- if hasattr(builtins, name):\r
- return 'builtin', getattr(builtins, name)\r
- return None, __UNDEF__\r
-\r
-def scanvars(reader, frame, locals):\r
- """Scan one logical line of Python and look up values of variables used."""\r
- vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__\r
- for ttype, token, start, end, line in tokenize.generate_tokens(reader):\r
- if ttype == tokenize.NEWLINE: break\r
- if ttype == tokenize.NAME and token not in keyword.kwlist:\r
- if lasttoken == '.':\r
- if parent is not __UNDEF__:\r
- value = getattr(parent, token, __UNDEF__)\r
- vars.append((prefix + token, prefix, value))\r
- else:\r
- where, value = lookup(token, frame, locals)\r
- vars.append((token, where, value))\r
- elif token == '.':\r
- prefix += lasttoken + '.'\r
- parent = value\r
- else:\r
- parent, prefix = None, ''\r
- lasttoken = token\r
- return vars\r
-\r
-def html(einfo, context=5):\r
- """Return a nice HTML document describing a given traceback."""\r
- etype, evalue, etb = einfo\r
- if type(etype) is types.ClassType:\r
- etype = etype.__name__\r
- pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable\r
- date = time.ctime(time.time())\r
- head = '<body bgcolor="#f0f0f8">' + pydoc.html.heading(\r
- '<big><big>%s</big></big>' %\r
- strong(pydoc.html.escape(str(etype))),\r
- '#ffffff', '#6622aa', pyver + '<br>' + date) + '''\r
-<p>A problem occurred in a Python script. Here is the sequence of\r
-function calls leading up to the error, in the order they occurred.</p>'''\r
-\r
- indent = '<tt>' + small(' ' * 5) + ' </tt>'\r
- frames = []\r
- records = inspect.getinnerframes(etb, context)\r
- for frame, file, lnum, func, lines, index in records:\r
- if file:\r
- file = os.path.abspath(file)\r
- link = '<a href="file://%s">%s</a>' % (file, pydoc.html.escape(file))\r
- else:\r
- file = link = '?'\r
- args, varargs, varkw, locals = inspect.getargvalues(frame)\r
- call = ''\r
- if func != '?':\r
- call = 'in ' + strong(func) + \\r
- inspect.formatargvalues(args, varargs, varkw, locals,\r
- formatvalue=lambda value: '=' + pydoc.html.repr(value))\r
-\r
- highlight = {}\r
- def reader(lnum=[lnum]):\r
- highlight[lnum[0]] = 1\r
- try: return linecache.getline(file, lnum[0])\r
- finally: lnum[0] += 1\r
- vars = scanvars(reader, frame, locals)\r
-\r
- rows = ['<tr><td bgcolor="#d8bbff">%s%s %s</td></tr>' %\r
- ('<big> </big>', link, call)]\r
- if index is not None:\r
- i = lnum - index\r
- for line in lines:\r
- num = small(' ' * (5-len(str(i))) + str(i)) + ' '\r
- if i in highlight:\r
- line = '<tt>=>%s%s</tt>' % (num, pydoc.html.preformat(line))\r
- rows.append('<tr><td bgcolor="#ffccee">%s</td></tr>' % line)\r
- else:\r
- line = '<tt> %s%s</tt>' % (num, pydoc.html.preformat(line))\r
- rows.append('<tr><td>%s</td></tr>' % grey(line))\r
- i += 1\r
-\r
- done, dump = {}, []\r
- for name, where, value in vars:\r
- if name in done: continue\r
- done[name] = 1\r
- if value is not __UNDEF__:\r
- if where in ('global', 'builtin'):\r
- name = ('<em>%s</em> ' % where) + strong(name)\r
- elif where == 'local':\r
- name = strong(name)\r
- else:\r
- name = where + strong(name.split('.')[-1])\r
- dump.append('%s = %s' % (name, pydoc.html.repr(value)))\r
- else:\r
- dump.append(name + ' <em>undefined</em>')\r
-\r
- rows.append('<tr><td>%s</td></tr>' % small(grey(', '.join(dump))))\r
- frames.append('''\r
-<table width="100%%" cellspacing=0 cellpadding=0 border=0>\r
-%s</table>''' % '\n'.join(rows))\r
-\r
- exception = ['<p>%s: %s' % (strong(pydoc.html.escape(str(etype))),\r
- pydoc.html.escape(str(evalue)))]\r
- if isinstance(evalue, BaseException):\r
- for name in dir(evalue):\r
- if name[:1] == '_': continue\r
- value = pydoc.html.repr(getattr(evalue, name))\r
- exception.append('\n<br>%s%s =\n%s' % (indent, name, value))\r
-\r
- return head + ''.join(frames) + ''.join(exception) + '''\r
-\r
-\r
-<!-- The above is a description of an error in a Python program, formatted\r
- for a Web browser because the 'cgitb' module was enabled. In case you\r
- are not reading this in a Web browser, here is the original traceback:\r
-\r
-%s\r
--->\r
-''' % pydoc.html.escape(\r
- ''.join(traceback.format_exception(etype, evalue, etb)))\r
-\r
-def text(einfo, context=5):\r
- """Return a plain text document describing a given traceback."""\r
- etype, evalue, etb = einfo\r
- if type(etype) is types.ClassType:\r
- etype = etype.__name__\r
- pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable\r
- date = time.ctime(time.time())\r
- head = "%s\n%s\n%s\n" % (str(etype), pyver, date) + '''\r
-A problem occurred in a Python script. Here is the sequence of\r
-function calls leading up to the error, in the order they occurred.\r
-'''\r
-\r
- frames = []\r
- records = inspect.getinnerframes(etb, context)\r
- for frame, file, lnum, func, lines, index in records:\r
- file = file and os.path.abspath(file) or '?'\r
- args, varargs, varkw, locals = inspect.getargvalues(frame)\r
- call = ''\r
- if func != '?':\r
- call = 'in ' + func + \\r
- inspect.formatargvalues(args, varargs, varkw, locals,\r
- formatvalue=lambda value: '=' + pydoc.text.repr(value))\r
-\r
- highlight = {}\r
- def reader(lnum=[lnum]):\r
- highlight[lnum[0]] = 1\r
- try: return linecache.getline(file, lnum[0])\r
- finally: lnum[0] += 1\r
- vars = scanvars(reader, frame, locals)\r
-\r
- rows = [' %s %s' % (file, call)]\r
- if index is not None:\r
- i = lnum - index\r
- for line in lines:\r
- num = '%5d ' % i\r
- rows.append(num+line.rstrip())\r
- i += 1\r
-\r
- done, dump = {}, []\r
- for name, where, value in vars:\r
- if name in done: continue\r
- done[name] = 1\r
- if value is not __UNDEF__:\r
- if where == 'global': name = 'global ' + name\r
- elif where != 'local': name = where + name.split('.')[-1]\r
- dump.append('%s = %s' % (name, pydoc.text.repr(value)))\r
- else:\r
- dump.append(name + ' undefined')\r
-\r
- rows.append('\n'.join(dump))\r
- frames.append('\n%s\n' % '\n'.join(rows))\r
-\r
- exception = ['%s: %s' % (str(etype), str(evalue))]\r
- if isinstance(evalue, BaseException):\r
- for name in dir(evalue):\r
- value = pydoc.text.repr(getattr(evalue, name))\r
- exception.append('\n%s%s = %s' % (" "*4, name, value))\r
-\r
- return head + ''.join(frames) + ''.join(exception) + '''\r
-\r
-The above is a description of an error in a Python program. Here is\r
-the original traceback:\r
-\r
-%s\r
-''' % ''.join(traceback.format_exception(etype, evalue, etb))\r
-\r
-class Hook:\r
- """A hook to replace sys.excepthook that shows tracebacks in HTML."""\r
-\r
- def __init__(self, display=1, logdir=None, context=5, file=None,\r
- format="html"):\r
- self.display = display # send tracebacks to browser if true\r
- self.logdir = logdir # log tracebacks to files if not None\r
- self.context = context # number of source code lines per frame\r
- self.file = file or sys.stdout # place to send the output\r
- self.format = format\r
-\r
- def __call__(self, etype, evalue, etb):\r
- self.handle((etype, evalue, etb))\r
-\r
- def handle(self, info=None):\r
- info = info or sys.exc_info()\r
- if self.format == "html":\r
- self.file.write(reset())\r
-\r
- formatter = (self.format=="html") and html or text\r
- plain = False\r
- try:\r
- doc = formatter(info, self.context)\r
- except: # just in case something goes wrong\r
- doc = ''.join(traceback.format_exception(*info))\r
- plain = True\r
-\r
- if self.display:\r
- if plain:\r
- doc = doc.replace('&', '&').replace('<', '<')\r
- self.file.write('<pre>' + doc + '</pre>\n')\r
- else:\r
- self.file.write(doc + '\n')\r
- else:\r
- self.file.write('<p>A problem occurred in a Python script.\n')\r
-\r
- if self.logdir is not None:\r
- suffix = ['.txt', '.html'][self.format=="html"]\r
- (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir)\r
- try:\r
- file = os.fdopen(fd, 'w')\r
- file.write(doc)\r
- file.close()\r
- msg = '<p> %s contains the description of this error.' % path\r
- except:\r
- msg = '<p> Tried to save traceback to %s, but failed.' % path\r
- self.file.write(msg + '\n')\r
- try:\r
- self.file.flush()\r
- except: pass\r
-\r
-handler = Hook().handle\r
-def enable(display=1, logdir=None, context=5, format="html"):\r
- """Install an exception handler that formats tracebacks as HTML.\r
-\r
- The optional argument 'display' can be set to 0 to suppress sending the\r
- traceback to the browser, and 'logdir' can be set to a directory to cause\r
- tracebacks to be written to files there."""\r
- sys.excepthook = Hook(display=display, logdir=logdir,\r
- context=context, format=format)\r