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