~malept/ubuntu/lucid/python2.6/dev-dependency-fix

« back to all changes in this revision

Viewing changes to Lib/cgitb.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-02-13 12:51:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090213125100-uufgcb9yeqzujpqw
Tags: upstream-2.6.1
ImportĀ upstreamĀ versionĀ 2.6.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""More comprehensive traceback formatting for Python scripts.
 
2
 
 
3
To enable this module, do:
 
4
 
 
5
    import cgitb; cgitb.enable()
 
6
 
 
7
at the top of your script.  The optional arguments to enable() are:
 
8
 
 
9
    display     - if true, tracebacks are displayed in the web browser
 
10
    logdir      - if set, tracebacks are written to files in this directory
 
11
    context     - number of lines of source code to show for each stack frame
 
12
    format      - 'text' or 'html' controls the output format
 
13
 
 
14
By default, tracebacks are displayed but not saved, the context is 5 lines
 
15
and the output format is 'html' (for backwards compatibility with the
 
16
original use of this module)
 
17
 
 
18
Alternatively, if you have caught an exception and want cgitb to display it
 
19
for you, call cgitb.handler().  The optional argument to handler() is a
 
20
3-item tuple (etype, evalue, etb) just like the value of sys.exc_info().
 
21
The default handler displays output as HTML.
 
22
"""
 
23
 
 
24
__author__ = 'Ka-Ping Yee'
 
25
 
 
26
__version__ = '$Revision: 55348 $'
 
27
 
 
28
import sys
 
29
 
 
30
def reset():
 
31
    """Return a string that resets the CGI and browser to a known state."""
 
32
    return '''<!--: spam
 
33
Content-Type: text/html
 
34
 
 
35
<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> -->
 
36
<body bgcolor="#f0f0f8"><font color="#f0f0f8" size="-5"> --> -->
 
37
</font> </font> </font> </script> </object> </blockquote> </pre>
 
38
</table> </table> </table> </table> </table> </font> </font> </font>'''
 
39
 
 
40
__UNDEF__ = []                          # a special sentinel object
 
41
def small(text):
 
42
    if text:
 
43
        return '<small>' + text + '</small>'
 
44
    else:
 
45
        return ''
 
46
 
 
47
def strong(text):
 
48
    if text:
 
49
        return '<strong>' + text + '</strong>'
 
50
    else:
 
51
        return ''
 
52
 
 
53
def grey(text):
 
54
    if text:
 
55
        return '<font color="#909090">' + text + '</font>'
 
56
    else:
 
57
        return ''
 
58
 
 
59
def lookup(name, frame, locals):
 
60
    """Find the value for a given name in the given environment."""
 
61
    if name in locals:
 
62
        return 'local', locals[name]
 
63
    if name in frame.f_globals:
 
64
        return 'global', frame.f_globals[name]
 
65
    if '__builtins__' in frame.f_globals:
 
66
        builtins = frame.f_globals['__builtins__']
 
67
        if type(builtins) is type({}):
 
68
            if name in builtins:
 
69
                return 'builtin', builtins[name]
 
70
        else:
 
71
            if hasattr(builtins, name):
 
72
                return 'builtin', getattr(builtins, name)
 
73
    return None, __UNDEF__
 
74
 
 
75
def scanvars(reader, frame, locals):
 
76
    """Scan one logical line of Python and look up values of variables used."""
 
77
    import tokenize, keyword
 
78
    vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__
 
79
    for ttype, token, start, end, line in tokenize.generate_tokens(reader):
 
80
        if ttype == tokenize.NEWLINE: break
 
81
        if ttype == tokenize.NAME and token not in keyword.kwlist:
 
82
            if lasttoken == '.':
 
83
                if parent is not __UNDEF__:
 
84
                    value = getattr(parent, token, __UNDEF__)
 
85
                    vars.append((prefix + token, prefix, value))
 
86
            else:
 
87
                where, value = lookup(token, frame, locals)
 
88
                vars.append((token, where, value))
 
89
        elif token == '.':
 
90
            prefix += lasttoken + '.'
 
91
            parent = value
 
92
        else:
 
93
            parent, prefix = None, ''
 
94
        lasttoken = token
 
95
    return vars
 
96
 
 
97
def html((etype, evalue, etb), context=5):
 
98
    """Return a nice HTML document describing a given traceback."""
 
99
    import os, types, time, traceback, linecache, inspect, pydoc
 
100
 
 
101
    if type(etype) is types.ClassType:
 
102
        etype = etype.__name__
 
103
    pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
 
104
    date = time.ctime(time.time())
 
105
    head = '<body bgcolor="#f0f0f8">' + pydoc.html.heading(
 
106
        '<big><big>%s</big></big>' %
 
107
        strong(pydoc.html.escape(str(etype))),
 
108
        '#ffffff', '#6622aa', pyver + '<br>' + date) + '''
 
109
<p>A problem occurred in a Python script.  Here is the sequence of
 
110
function calls leading up to the error, in the order they occurred.</p>'''
 
111
 
 
112
    indent = '<tt>' + small('&nbsp;' * 5) + '&nbsp;</tt>'
 
113
    frames = []
 
114
    records = inspect.getinnerframes(etb, context)
 
115
    for frame, file, lnum, func, lines, index in records:
 
116
        if file:
 
117
            file = os.path.abspath(file)
 
118
            link = '<a href="file://%s">%s</a>' % (file, pydoc.html.escape(file))
 
119
        else:
 
120
            file = link = '?'
 
121
        args, varargs, varkw, locals = inspect.getargvalues(frame)
 
122
        call = ''
 
123
        if func != '?':
 
124
            call = 'in ' + strong(func) + \
 
125
                inspect.formatargvalues(args, varargs, varkw, locals,
 
126
                    formatvalue=lambda value: '=' + pydoc.html.repr(value))
 
127
 
 
128
        highlight = {}
 
129
        def reader(lnum=[lnum]):
 
130
            highlight[lnum[0]] = 1
 
131
            try: return linecache.getline(file, lnum[0])
 
132
            finally: lnum[0] += 1
 
133
        vars = scanvars(reader, frame, locals)
 
134
 
 
135
        rows = ['<tr><td bgcolor="#d8bbff">%s%s %s</td></tr>' %
 
136
                ('<big>&nbsp;</big>', link, call)]
 
137
        if index is not None:
 
138
            i = lnum - index
 
139
            for line in lines:
 
140
                num = small('&nbsp;' * (5-len(str(i))) + str(i)) + '&nbsp;'
 
141
                line = '<tt>%s%s</tt>' % (num, pydoc.html.preformat(line))
 
142
                if i in highlight:
 
143
                    rows.append('<tr><td bgcolor="#ffccee">%s</td></tr>' % line)
 
144
                else:
 
145
                    rows.append('<tr><td>%s</td></tr>' % grey(line))
 
146
                i += 1
 
147
 
 
148
        done, dump = {}, []
 
149
        for name, where, value in vars:
 
150
            if name in done: continue
 
151
            done[name] = 1
 
152
            if value is not __UNDEF__:
 
153
                if where in ('global', 'builtin'):
 
154
                    name = ('<em>%s</em> ' % where) + strong(name)
 
155
                elif where == 'local':
 
156
                    name = strong(name)
 
157
                else:
 
158
                    name = where + strong(name.split('.')[-1])
 
159
                dump.append('%s&nbsp;= %s' % (name, pydoc.html.repr(value)))
 
160
            else:
 
161
                dump.append(name + ' <em>undefined</em>')
 
162
 
 
163
        rows.append('<tr><td>%s</td></tr>' % small(grey(', '.join(dump))))
 
164
        frames.append('''
 
165
<table width="100%%" cellspacing=0 cellpadding=0 border=0>
 
166
%s</table>''' % '\n'.join(rows))
 
167
 
 
168
    exception = ['<p>%s: %s' % (strong(pydoc.html.escape(str(etype))),
 
169
                                pydoc.html.escape(str(evalue)))]
 
170
    if isinstance(evalue, BaseException):
 
171
        for name in dir(evalue):
 
172
            if name[:1] == '_': continue
 
173
            value = pydoc.html.repr(getattr(evalue, name))
 
174
            exception.append('\n<br>%s%s&nbsp;=\n%s' % (indent, name, value))
 
175
 
 
176
    import traceback
 
177
    return head + ''.join(frames) + ''.join(exception) + '''
 
178
 
 
179
 
 
180
<!-- The above is a description of an error in a Python program, formatted
 
181
     for a Web browser because the 'cgitb' module was enabled.  In case you
 
182
     are not reading this in a Web browser, here is the original traceback:
 
183
 
 
184
%s
 
185
-->
 
186
''' % pydoc.html.escape(
 
187
          ''.join(traceback.format_exception(etype, evalue, etb)))
 
188
 
 
189
def text((etype, evalue, etb), context=5):
 
190
    """Return a plain text document describing a given traceback."""
 
191
    import os, types, time, traceback, linecache, inspect, pydoc
 
192
 
 
193
    if type(etype) is types.ClassType:
 
194
        etype = etype.__name__
 
195
    pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
 
196
    date = time.ctime(time.time())
 
197
    head = "%s\n%s\n%s\n" % (str(etype), pyver, date) + '''
 
198
A problem occurred in a Python script.  Here is the sequence of
 
199
function calls leading up to the error, in the order they occurred.
 
200
'''
 
201
 
 
202
    frames = []
 
203
    records = inspect.getinnerframes(etb, context)
 
204
    for frame, file, lnum, func, lines, index in records:
 
205
        file = file and os.path.abspath(file) or '?'
 
206
        args, varargs, varkw, locals = inspect.getargvalues(frame)
 
207
        call = ''
 
208
        if func != '?':
 
209
            call = 'in ' + func + \
 
210
                inspect.formatargvalues(args, varargs, varkw, locals,
 
211
                    formatvalue=lambda value: '=' + pydoc.text.repr(value))
 
212
 
 
213
        highlight = {}
 
214
        def reader(lnum=[lnum]):
 
215
            highlight[lnum[0]] = 1
 
216
            try: return linecache.getline(file, lnum[0])
 
217
            finally: lnum[0] += 1
 
218
        vars = scanvars(reader, frame, locals)
 
219
 
 
220
        rows = [' %s %s' % (file, call)]
 
221
        if index is not None:
 
222
            i = lnum - index
 
223
            for line in lines:
 
224
                num = '%5d ' % i
 
225
                rows.append(num+line.rstrip())
 
226
                i += 1
 
227
 
 
228
        done, dump = {}, []
 
229
        for name, where, value in vars:
 
230
            if name in done: continue
 
231
            done[name] = 1
 
232
            if value is not __UNDEF__:
 
233
                if where == 'global': name = 'global ' + name
 
234
                elif where != 'local': name = where + name.split('.')[-1]
 
235
                dump.append('%s = %s' % (name, pydoc.text.repr(value)))
 
236
            else:
 
237
                dump.append(name + ' undefined')
 
238
 
 
239
        rows.append('\n'.join(dump))
 
240
        frames.append('\n%s\n' % '\n'.join(rows))
 
241
 
 
242
    exception = ['%s: %s' % (str(etype), str(evalue))]
 
243
    if isinstance(evalue, BaseException):
 
244
        for name in dir(evalue):
 
245
            value = pydoc.text.repr(getattr(evalue, name))
 
246
            exception.append('\n%s%s = %s' % (" "*4, name, value))
 
247
 
 
248
    import traceback
 
249
    return head + ''.join(frames) + ''.join(exception) + '''
 
250
 
 
251
The above is a description of an error in a Python program.  Here is
 
252
the original traceback:
 
253
 
 
254
%s
 
255
''' % ''.join(traceback.format_exception(etype, evalue, etb))
 
256
 
 
257
class Hook:
 
258
    """A hook to replace sys.excepthook that shows tracebacks in HTML."""
 
259
 
 
260
    def __init__(self, display=1, logdir=None, context=5, file=None,
 
261
                 format="html"):
 
262
        self.display = display          # send tracebacks to browser if true
 
263
        self.logdir = logdir            # log tracebacks to files if not None
 
264
        self.context = context          # number of source code lines per frame
 
265
        self.file = file or sys.stdout  # place to send the output
 
266
        self.format = format
 
267
 
 
268
    def __call__(self, etype, evalue, etb):
 
269
        self.handle((etype, evalue, etb))
 
270
 
 
271
    def handle(self, info=None):
 
272
        info = info or sys.exc_info()
 
273
        if self.format == "html":
 
274
            self.file.write(reset())
 
275
 
 
276
        formatter = (self.format=="html") and html or text
 
277
        plain = False
 
278
        try:
 
279
            doc = formatter(info, self.context)
 
280
        except:                         # just in case something goes wrong
 
281
            import traceback
 
282
            doc = ''.join(traceback.format_exception(*info))
 
283
            plain = True
 
284
 
 
285
        if self.display:
 
286
            if plain:
 
287
                doc = doc.replace('&', '&amp;').replace('<', '&lt;')
 
288
                self.file.write('<pre>' + doc + '</pre>\n')
 
289
            else:
 
290
                self.file.write(doc + '\n')
 
291
        else:
 
292
            self.file.write('<p>A problem occurred in a Python script.\n')
 
293
 
 
294
        if self.logdir is not None:
 
295
            import os, tempfile
 
296
            suffix = ['.txt', '.html'][self.format=="html"]
 
297
            (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir)
 
298
            try:
 
299
                file = os.fdopen(fd, 'w')
 
300
                file.write(doc)
 
301
                file.close()
 
302
                msg = '<p> %s contains the description of this error.' % path
 
303
            except:
 
304
                msg = '<p> Tried to save traceback to %s, but failed.' % path
 
305
            self.file.write(msg + '\n')
 
306
        try:
 
307
            self.file.flush()
 
308
        except: pass
 
309
 
 
310
handler = Hook().handle
 
311
def enable(display=1, logdir=None, context=5, format="html"):
 
312
    """Install an exception handler that formats tracebacks as HTML.
 
313
 
 
314
    The optional argument 'display' can be set to 0 to suppress sending the
 
315
    traceback to the browser, and 'logdir' can be set to a directory to cause
 
316
    tracebacks to be written to files there."""
 
317
    sys.excepthook = Hook(display=display, logdir=logdir,
 
318
                          context=context, format=format)