docs: def get_frame_info(tb, context_lines=7, simple=False):
      """
      Return a dict of information about a given traceback.
      """
      # line numbers / function / variables
      lineno = tb.tb_lineno
      function = tb.tb_frame.f_code.co_name
      variables = tb.tb_frame.f_locals
  
      files = {}
  
      # get filename
      if simple:
          fn = tb.tb_frame.f_code.co_filename
      else:
          fn = tb.tb_frame.f_globals.get('__file__')
          if not fn:
              fn = os.path.realpath(inspect.getsourcefile(tb) or
                                    inspect.getfile(tb))
          if fn[-4:] in ('.pyc', '.pyo'):
              fn = fn[:-1]
  
      #if filename is existed, then just read the file
      # get loader
      loader = None
      if not os.path.exists(fn):
          loader = tb.tb_frame.f_globals.get('__loader__')
          while not loader and tb.tb_next:
              tb = tb.tb_next
              loader = tb.tb_frame.f_globals.get('__loader__')
  
  
      # sourcecode
      source = ''
      pre_context, post_context = [], []
      context_line = raw_context_line = context_lineno = None
      try:
          if loader:
              source = loader.get_source(fn)
          else:
              if not fn in files:
                  source = open(fn).read()
                  files[fn] = source
              else:
                  source = files[fn]
      except:
          pass
      else:
          try:
              raw_context_line = source.splitlines()[lineno - 1].strip()
          except IndexError:
              pass
          if not simple:
              parsed_source = highlight_python(source)
              lbound = max(0, lineno - context_lines - 1)
              ubound = lineno + context_lines
              try:
                  context_line = parsed_source[lineno - 1]
                  pre_context = parsed_source[lbound:lineno - 1]
                  post_context = parsed_source[lineno:ubound]
              except IndexError as e:
                  pass
              context_lineno = lbound
  
      if isinstance(fn, unicode):
          fn = fn.encode('utf-8')
      return {
          'tb':               tb,
          'filename':         fn,
          'basename':         os.path.basename(fn),
          'loader':           loader,
          'function':         function,
          'lineno':           lineno,
          'vars':             variables,
          'pre_context':      pre_context,
          'context_line':     context_line,
          'raw_context_line': raw_context_line,
          'post_context':     post_context,
          'context_lineno':   context_lineno,
          'source':           source
      }