python-2.5.2/win32/Lib/cgitb.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     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: 55349 $'
       
    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)