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