diff --git a/Lib/cgitb.py b/Lib/cgitb.py new file mode 100644 index 00000000000..8084464fa6f --- /dev/null +++ b/Lib/cgitb.py @@ -0,0 +1,182 @@ +"""Handle exceptions in CGI scripts by formatting tracebacks into nice HTML. + +To enable this module, do: + + import cgitb; cgitb.enable() + +at the top of your CGI script. The optional arguments to enable() are: + + display - if true, tracebacks are displayed in the web browser + logdir - if set, tracebacks are written to files in this directory + +By default, tracebacks are displayed but not written to files. + +Alternatively, if you have caught an exception and want cgitb to display it +for you, call cgitb.handle(). The optional argument to handle() is a 3-item +tuple (etype, evalue, etb) just like the value of sys.exc_info().""" + +__author__ = 'Ka-Ping Yee' +__version__ = '$Revision$' + +def reset(): + """Return a string that resets the CGI and browser to a known state.""" + return ''' +
--> --> + + ''' + +def html(etype, evalue, etb, context=5): + """Return a nice HTML document describing the traceback.""" + import sys, os, types, time, traceback + import keyword, tokenize, linecache, inspect, pydoc + + if type(etype) is types.ClassType: + etype = etype.__name__ + pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable + date = time.ctime(time.time()) + head = '' + pydoc.html.heading( + '%s' % str(etype), + '#ffffff', '#aa55cc', pyver + 'A problem occurred in a Python script.
+Here is the sequence of function calls leading up to
+the error, with the most recent (innermost) call last.'''
+
+ indent = '' + ' ' * 5 + ' '
+ frames = []
+ records = inspect.getinnerframes(etb, context)
+ for frame, file, lnum, func, lines, index in records:
+ file = file and os.path.abspath(file) or '?'
+ link = '%s' % (file, pydoc.html.escape(file))
+ args, varargs, varkw, locals = inspect.getargvalues(frame)
+ if func == '?':
+ call = ''
+ else:
+ def eqrepr(value): return '=' + pydoc.html.repr(value)
+ call = 'in %s' % func + inspect.formatargvalues(
+ args, varargs, varkw, locals, formatvalue=eqrepr)
+
+ names = []
+ def tokeneater(type, token, start, end, line):
+ if type == tokenize.NAME and token not in keyword.kwlist:
+ if token not in names: names.append(token)
+ if type == tokenize.NEWLINE: raise IndexError
+ def linereader(lnum=[lnum]):
+ line = linecache.getline(file, lnum[0])
+ lnum[0] += 1
+ return line
+
+ try:
+ tokenize.tokenize(linereader, tokeneater)
+ except IndexError: pass
+ lvals = []
+ for name in names:
+ if name in frame.f_code.co_varnames:
+ if locals.has_key(name):
+ value = pydoc.html.repr(locals[name])
+ else:
+ value = 'undefined'
+ name = '%s' % name
+ else:
+ if frame.f_globals.has_key(name):
+ value = pydoc.html.repr(frame.f_globals[name])
+ else:
+ value = 'undefined'
+ name = 'global %s' % name
+ lvals.append('%s = %s' % (name, value))
+ if lvals:
+ lvals = indent + '''
+%s
''' % (', '.join(lvals))
+ else:
+ lvals = ''
+
+ level = '''
+
%s %s |
%s |
' + level + '\n'.join(excerpt)) + + exception = ['
%s: %s' % (str(etype), str(evalue))]
+ if type(evalue) is types.InstanceType:
+ for name in dir(evalue):
+ value = pydoc.html.repr(getattr(evalue, name))
+ exception.append('\n
%s%s =\n%s' % (indent, name, value))
+
+ import traceback
+ plaintrace = ''.join(traceback.format_exception(etype, evalue, etb))
+
+ return head + ''.join(frames) + ''.join(exception) + '''
+
+
+
+''' % plaintrace
+
+class Hook:
+ def __init__(self, display=1, logdir=None):
+ self.display = display # send tracebacks to browser if true
+ self.logdir = logdir # log tracebacks to files if not None
+
+ def __call__(self, etype, evalue, etb):
+ """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
+ self.handle((etype, evalue, etb))
+
+ def handle(self, info=None):
+ import sys, os
+ info = info or sys.exc_info()
+ text = 0
+ print reset()
+
+ try:
+ doc = html(*info)
+ except: # just in case something goes wrong
+ import traceback
+ doc = ''.join(traceback.format_exception(*info))
+ text = 1
+
+ if self.display:
+ if text:
+ doc = doc.replace('&', '&').replace('<', '<')
+ print '
', doc, '' + else: + print doc + else: + print '
A problem occurred in a Python script.' + + if self.logdir is not None: + import tempfile + name = tempfile.mktemp(['.html', '.txt'][text]) + path = os.path.join(self.logdir, os.path.basename(name)) + try: + file = open(path, 'w') + file.write(doc) + file.close() + print '
%s contains the description of this error.' % path + except: + print '
Tried to write to %s, but failed.' % path + +handler = Hook().handle +def enable(display=1, logdir=None): + import sys + sys.excepthook = Hook(display, logdir)