Code

- replaced the content() callback ickiness with Page Template macro usage
[roundup.git] / roundup / cgi / cgitb.py
1 #
2 # This module was written by Ka-Ping Yee, <ping@lfw.org>.
3
4 # $Id: cgitb.py,v 1.7 2002-09-25 02:10:25 richard Exp $
6 __doc__ = """
7 Extended CGI traceback handler by Ka-Ping Yee, <ping@lfw.org>.
8 """
10 import sys, os, types, string, keyword, linecache, tokenize, inspect, cgi
11 import pydoc, traceback
13 from roundup.i18n import _
15 def breaker():
16     return ('<body bgcolor="white">' +
17             '<font color="white" size="-5"> > </font> ' +
18             '</table>' * 5)
20 def niceDict(indent, dict):
21     l = []
22     for k,v in dict.items():
23         l.append('<tr><td><strong>%s</strong></td><td>%s</td></tr>'%(k,
24             cgi.escape(repr(v))))
25     return '\n'.join(l)
27 def pt_html(context=5):
28     l = ['<h1>Templating Error</h1>'
29          '<p class="help">Debugging information follows</p>'
30          '<ol>']
31     from roundup.cgi.PageTemplates.Expressions import TraversalError
32     t = inspect.trace(context)
33     t.reverse()
34     for frame, file, lnum, func, lines, index in t:
35         args, varargs, varkw, locals = inspect.getargvalues(frame)
36         if locals.has_key('__traceback_info__'):
37             ti = locals['__traceback_info__']
38             if isinstance(ti, TraversalError):
39                 s = []
40                 for name, info in ti.path:
41                     s.append('<li>"%s" (%s)</li>'%(name,cgi.escape(repr(info))))
42                 s = '\n'.join(s)
43                 l.append('<li>Looking for "%s", current path:<ol>%s</ol></li>'%(
44                     ti.name, s))
45             else:
46                 l.append('<li>In %s</li>'%cgi.escape(str(ti)))
47         if locals.has_key('__traceback_supplement__'):
48             ts = locals['__traceback_supplement__']
49             if len(ts) == 2:
50                 supp, context = ts
51                 s = 'A problem occurred in your template "%s".'%str(context.id)
52                 if context._v_errors:
53                     s = s + '<br>' + '<br>'.join(
54                         [cgi.escape(x) for x in context._v_errors])
55                 l.append('<li>%s</li>'%s)
56             elif len(ts) == 3:
57                 supp, context, info = ts
58                 l.append('''
59 <li>While evaluating the %r expression on line %d
60 <table class="otherinfo" style="font-size: 90%%">
61  <tr><th colspan="2" class="header">Current variables:</th></tr>
62  %s
63  %s
64 </table></li>
65 '''%(info, context.position[0], niceDict('    ', context.global_vars),
66      niceDict('    ', context.local_vars)))
68     l.append('''
69 </ol>
70 <table style="font-size: 80%%; color: gray">
71  <tr><th class="header" align="left">Full traceback:</th></tr>
72  <tr><td><pre>%s</pre></td></tr>
73 </table>'''%cgi.escape(''.join(traceback.format_exception(sys.exc_type,
74         sys.exc_value, sys.exc_traceback))))
75     l.append('<p>&nbsp;</p>')
76     return '\n'.join(l)
78 def html(context=5):
79     etype, evalue = sys.exc_type, sys.exc_value
80     if type(etype) is types.ClassType:
81         etype = etype.__name__
82     pyver = 'Python ' + string.split(sys.version)[0] + '<br>' + sys.executable
83     head = pydoc.html.heading(
84         '<font size=+1><strong>%s</strong>: %s</font>'%(etype, evalue),
85         '#ffffff', '#777777', pyver)
87     head = head + (_('<p>A problem occurred while running a Python script. '
88                    'Here is the sequence of function calls leading up to '
89                    'the error, with the most recent (innermost) call first. '
90                    'The exception attributes are:'))
92     indent = '<tt><small>%s</small>&nbsp;</tt>' % ('&nbsp;' * 5)
93     traceback = []
94     for frame, file, lnum, func, lines, index in inspect.trace(context):
95         if file is None:
96             link = '''&lt;file is None - probably inside <tt>eval</tt> or
97                     <tt>exec</tt>&gt;'''
98         else:
99             file = os.path.abspath(file)
100             link = '<a href="file:%s">%s</a>' % (file, pydoc.html.escape(file))
101         args, varargs, varkw, locals = inspect.getargvalues(frame)
102         if func == '?':
103             call = ''
104         else:
105             call = 'in <strong>%s</strong>' % func + inspect.formatargvalues(
106                     args, varargs, varkw, locals,
107                     formatvalue=lambda value: '=' + pydoc.html.repr(value))
109         level = '''
110 <table width="100%%" bgcolor="#dddddd" cellspacing=0 cellpadding=2 border=0>
111 <tr><td>%s %s</td></tr></table>''' % (link, call)
113         if index is None or file is None:
114             traceback.append('<p>' + level)
115             continue
117         # do a file inspection
118         names = []
119         def tokeneater(type, token, start, end, line, names=names):
120             if type == tokenize.NAME and token not in keyword.kwlist:
121                 if token not in names:
122                     names.append(token)
123             if type == tokenize.NEWLINE: raise IndexError
124         def linereader(file=file, lnum=[lnum]):
125             line = linecache.getline(file, lnum[0])
126             lnum[0] = lnum[0] + 1
127             return line
129         try:
130             tokenize.tokenize(linereader, tokeneater)
131         except IndexError:
132             pass
133         lvals = []
134         for name in names:
135             if name in frame.f_code.co_varnames:
136                 if locals.has_key(name):
137                     value = pydoc.html.repr(locals[name])
138                 else:
139                     value = _('<em>undefined</em>')
140                 name = '<strong>%s</strong>' % name
141             else:
142                 if frame.f_globals.has_key(name):
143                     value = pydoc.html.repr(frame.f_globals[name])
144                 else:
145                     value = _('<em>undefined</em>')
146                 name = '<em>global</em> <strong>%s</strong>' % name
147             lvals.append('%s&nbsp;= %s'%(name, value))
148         if lvals:
149             lvals = string.join(lvals, ', ')
150             lvals = indent + '<small><font color="#909090">%s'\
151                 '</font></small><br>'%lvals
152         else:
153             lvals = ''
155         excerpt = []
156         i = lnum - index
157         for line in lines:
158             number = '&nbsp;' * (5-len(str(i))) + str(i)
159             number = '<small><font color="#909090">%s</font></small>' % number
160             line = '<tt>%s&nbsp;%s</tt>' % (number, pydoc.html.preformat(line))
161             if i == lnum:
162                 line = '''
163 <table width="100%%" bgcolor="#white" cellspacing=0 cellpadding=0 border=0>
164 <tr><td>%s</td></tr></table>''' % line
165             excerpt.append('\n' + line)
166             if i == lnum:
167                 excerpt.append(lvals)
168             i = i + 1
169         traceback.append('<p>' + level + string.join(excerpt, '\n'))
171     traceback.reverse()
173     exception = '<p><strong>%s</strong>: %s' % (str(etype), str(evalue))
174     attribs = []
175     if type(evalue) is types.InstanceType:
176         for name in dir(evalue):
177             value = pydoc.html.repr(getattr(evalue, name))
178             attribs.append('<br>%s%s&nbsp;= %s' % (indent, name, value))
180     return head + string.join(attribs) + string.join(traceback) + '<p>&nbsp;</p>'
182 def handler():
183     print breaker()
184     print html()
186 # vim: set filetype=python ts=4 sw=4 et si