[Python-checkins] CVS: python/dist/src/Lib cgitb.py,1.1,1.1.2.1
Barry Warsaw
bwarsaw@users.sourceforge.net
Tue, 21 Aug 2001 05:49:07 -0700
Update of /cvsroot/python/python/dist/src/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv3386
Modified Files:
Tag: r22a2-branch
cgitb.py
Log Message:
Merging in Ka-Ping's changes from the trunk:
Enhancements:
- file URL now starts with "file://" (standard) rather than "file:"
- new optional argument 'context' to enable()
- repeated variable names don't have their values shown twice
- dotted attributes are shown; missing attributes handled reasonably
- highlight the whole logical line even if it has multiple physical lines
- use nice generator interface to tokenize
- formatting fixed so that it looks good in lynx, links, and w3m too
Index: cgitb.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/cgitb.py,v
retrieving revision 1.1
retrieving revision 1.1.2.1
diff -C2 -d -r1.1 -r1.1.2.1
*** cgitb.py 2001/08/18 04:04:50 1.1
--- cgitb.py 2001/08/21 12:49:05 1.1.2.1
***************
*** 9,14 ****
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
--- 9,15 ----
display - if true, tracebacks are displayed in the web browser
logdir - if set, tracebacks are written to files in this directory
+ context - number of lines of source code to show for each stack frame
! By default, tracebacks are displayed but not saved, and context is 5.
Alternatively, if you have caught an exception and want cgitb to display it
***************
*** 24,36 ****
Content-Type: text/html
! <body bgcolor="#f0f0ff"><font color="#f0f0ff" size="-5"> -->
! <body bgcolor="#f0f0ff"><font color="#f0f0ff" size="-5"> --> -->
</font> </font> </font> </script> </object> </blockquote> </pre>
</table> </table> </table> </table> </table> </font> </font> </font>'''
! 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:
--- 25,71 ----
Content-Type: text/html
! <body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> -->
! <body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> -->
</font> </font> </font> </script> </object> </blockquote> </pre>
</table> </table> </table> </table> </table> </font> </font> </font>'''
! __UNDEF__ = [] # a special sentinel object
! def small(text): return '<small>' + text + '</small>'
! def strong(text): return '<strong>' + text + '</strong>'
! def grey(text): return '<font color="#909090">' + text + '</font>'
!
! def lookup(name, frame, locals):
! """Find the value for a given name in the given environment."""
! if name in locals:
! return 'local', locals[name]
! if name in frame.f_globals:
! return 'global', frame.f_globals[name]
! return None, __UNDEF__
!
! def scanvars(reader, frame, locals):
! """Scan one logical line of Python and look up values of variables used."""
! import tokenize, keyword
! vars, lasttoken, parent, prefix = [], None, None, ''
! for ttype, token, start, end, line in tokenize.generate_tokens(reader):
! if ttype == tokenize.NEWLINE: break
! if ttype == tokenize.NAME and token not in keyword.kwlist:
! if lasttoken == '.':
! if parent is not __UNDEF__:
! value = getattr(parent, token, __UNDEF__)
! vars.append((prefix + token, prefix, value))
! else:
! where, value = lookup(token, frame, locals)
! vars.append((token, where, value))
! elif token == '.':
! prefix += lasttoken + '.'
! parent = value
! else:
! parent, prefix = None, ''
! lasttoken = token
! return vars
!
! def html((etype, evalue, etb), context=5):
! """Return a nice HTML document describing a given traceback."""
! import sys, os, types, time, traceback, linecache, inspect, pydoc
if type(etype) is types.ClassType:
***************
*** 38,117 ****
pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
date = time.ctime(time.time())
! head = '<body bgcolor="#f0f0ff">' + pydoc.html.heading(
'<big><big><strong>%s</strong></big></big>' % str(etype),
! '#ffffff', '#aa55cc', pyver + '<br>' + date) + '''
! <p>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 = '<tt><small>' + ' ' * 5 + '</small> </tt>'
frames = []
records = inspect.getinnerframes(etb, context)
for frame, file, lnum, func, lines, index in records:
file = file and os.path.abspath(file) or '?'
! link = '<a href="file:%s">%s</a>' % (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 <strong>%s</strong>' % 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 = '<em>undefined</em>'
! name = '<strong>%s</strong>' % name
! else:
! if frame.f_globals.has_key(name):
! value = pydoc.html.repr(frame.f_globals[name])
! else:
! value = '<em>undefined</em>'
! name = '<em>global</em> <strong>%s</strong>' % name
! lvals.append('%s = %s' % (name, value))
! if lvals:
! lvals = indent + '''
! <small><font color="#909090">%s</font></small><br>''' % (', '.join(lvals))
! else:
! lvals = ''
! level = '''
! <table width="100%%" bgcolor="#d8bbff" cellspacing=0 cellpadding=2 border=0>
! <tr><td>%s %s</td></tr></table>\n''' % (link, call)
! excerpt = []
if index is not None:
i = lnum - index
for line in lines:
! num = '<small><font color="#909090">%s</font></small>' % (
! ' ' * (5-len(str(i))) + str(i))
! line = '<tt>%s %s</tt>' % (num, pydoc.html.preformat(line))
! if i == lnum:
! line = '''
! <table width="100%%" bgcolor="#ffccee" cellspacing=0 cellpadding=0 border=0>
! <tr><td>%s</td></tr></table>\n''' % line
! excerpt.append('\n' + line)
! if i == lnum:
! excerpt.append(lvals)
! i = i + 1
! frames.append('<p>' + level + '\n'.join(excerpt))
! exception = ['<p><strong>%s</strong>: %s' % (str(etype), str(evalue))]
if type(evalue) is types.InstanceType:
for name in dir(evalue):
--- 73,133 ----
pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
date = time.ctime(time.time())
! head = '<body bgcolor="#f0f0f8">' + pydoc.html.heading(
'<big><big><strong>%s</strong></big></big>' % str(etype),
! '#ffffff', '#6622aa', pyver + '<br>' + date) + '''
! <p>A problem occurred in a Python script. Here is the sequence of
! function calls leading up to the error, in the order they occurred.'''
! indent = '<tt>' + small(' ' * 5) + ' </tt>'
frames = []
records = inspect.getinnerframes(etb, context)
for frame, file, lnum, func, lines, index in records:
file = file and os.path.abspath(file) or '?'
! link = '<a href="file://%s">%s</a>' % (file, pydoc.html.escape(file))
args, varargs, varkw, locals = inspect.getargvalues(frame)
! call = ''
! if func != '?':
! call = 'in ' + strong(func) + \
! inspect.formatargvalues(args, varargs, varkw, locals,
! formatvalue=lambda value: '=' + pydoc.html.repr(value))
! highlight = {}
! def reader(lnum=[lnum]):
! highlight[lnum[0]] = 1
! try: return linecache.getline(file, lnum[0])
! finally: lnum[0] += 1
! vars = scanvars(reader, frame, locals)
! rows = ['<tr><td bgcolor="#d8bbff">%s%s %s</td></tr>' %
! ('<big> </big>', link, call)]
if index is not None:
i = lnum - index
for line in lines:
! num = small(' ' * (5-len(str(i))) + str(i)) + ' '
! line = '<tt>%s%s</tt>' % (num, pydoc.html.preformat(line))
! if i in highlight:
! rows.append('<tr><td bgcolor="#ffccee">%s</td></tr>' % line)
! else:
! rows.append('<tr><td>%s</td></tr>' % grey(line))
! i += 1
! done, dump = {}, []
! for name, where, value in vars:
! if name in done: continue
! done[name] = 1
! if value is not __UNDEF__:
! if where == 'global': name = '<em>global</em> ' + strong(name)
! elif where == 'local': name = strong(name)
! else: name = where + strong(name.split('.')[-1])
! dump.append('%s = %s' % (name, pydoc.html.repr(value)))
! else:
! dump.append(name + ' <em>undefined</em>')
!
! rows.append('<tr><td>%s</td></tr>' % small(grey(', '.join(dump))))
! frames.append('''<p>
! <table width="100%%" cellspacing=0 cellpadding=0 border=0>
! %s</table>''' % '\n'.join(rows))
!
! exception = ['<p>%s: %s' % (strong(str(etype)), str(evalue))]
if type(evalue) is types.InstanceType:
for name in dir(evalue):
***************
*** 120,163 ****
import traceback
- plaintrace = ''.join(traceback.format_exception(etype, evalue, etb))
-
return head + ''.join(frames) + ''.join(exception) + '''
! <!-- The above is a description of an error that occurred in a Python program.
! It is formatted for display in a Web browser because it appears that
! we are running in a CGI environment. In case you are viewing this
! message outside of a Web browser, here is the original error traceback:
%s
-->
! ''' % 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 '<pre>', doc, '</pre>'
else:
print doc
--- 136,176 ----
import traceback
return head + ''.join(frames) + ''.join(exception) + '''
! <!-- The above is a description of an error in a Python program, formatted
! for a Web browser because the 'cgitb' module was enabled. In case you
! are not reading this in a Web browser, here is the original traceback:
%s
-->
! ''' % ''.join(traceback.format_exception(etype, evalue, etb))
class Hook:
! """A hook to replace sys.excepthook that shows tracebacks in HTML."""
!
! def __init__(self, display=1, logdir=None, context=5):
self.display = display # send tracebacks to browser if true
self.logdir = logdir # log tracebacks to files if not None
+ self.context = context # number of source code lines per frame
def __call__(self, etype, evalue, etb):
self.handle((etype, evalue, etb))
def handle(self, info=None):
! import sys
info = info or sys.exc_info()
print reset()
try:
! text, doc = 0, html(info, self.context)
except: # just in case something goes wrong
import traceback
! text, doc = 1, ''.join(traceback.format_exception(*info))
if self.display:
if text:
doc = doc.replace('&', '&').replace('<', '<')
! print '<pre>' + doc + '</pre>'
else:
print doc
***************
*** 166,170 ****
if self.logdir is not None:
! import tempfile
name = tempfile.mktemp(['.html', '.txt'][text])
path = os.path.join(self.logdir, os.path.basename(name))
--- 179,183 ----
if self.logdir is not None:
! import os, tempfile
name = tempfile.mktemp(['.html', '.txt'][text])
path = os.path.join(self.logdir, os.path.basename(name))
***************
*** 173,182 ****
file.write(doc)
file.close()
! print '<p>%s contains the description of this error.' % path
except:
! print '<p>Tried to write to %s, but failed.' % path
handler = Hook().handle
! def enable(display=1, logdir=None):
import sys
! sys.excepthook = Hook(display, logdir)
--- 186,200 ----
file.write(doc)
file.close()
! print '<p> %s contains the description of this error.' % path
except:
! print '<p> Tried to save traceback to %s, but failed.' % path
handler = Hook().handle
! def enable(display=1, logdir=None, context=5):
! """Install an exception handler that formats tracebacks as HTML.
!
! The optional argument 'display' can be set to 0 to suppress sending the
! traceback to the browser, and 'logdir' can be set to a directory to cause
! tracebacks to be written to files there."""
import sys
! sys.excepthook = Hook(display, logdir, context)