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
    }
Return a dict of information about a given traceback.