コード例 #1
0
def _StackSummary_extract(frame_gen,
                          limit=None,
                          lookup_lines=True,
                          capture_locals=False):
    """Create a StackSummary from a traceback or stack object.
    Very simplified copy of the original StackSummary.extract().
    We want always to capture locals, that is why we overwrite it.
    Additionally, we also capture the frame.
    This is a bit hacky and also not like this is originally intended (to not keep refs).

    :param frame_gen: A generator that yields (frame, lineno) tuples to
        include in the stack.
    :param limit: None to include all frames or the number of frames to
        include.
    :param lookup_lines: If True, lookup lines for each frame immediately,
        otherwise lookup is deferred until the frame is rendered.
    :param capture_locals: If True, the local variables from each frame will
        be captured as object representations into the FrameSummary.
    """
    result = StackSummary()
    for f, lineno in frame_gen:
        co = f.f_code
        filename = co.co_filename
        name = co.co_name
        result.append(
            ExtendedFrameSummary(frame=f,
                                 filename=filename,
                                 lineno=lineno,
                                 name=name,
                                 lookup_line=False))
    return result
コード例 #2
0
def _remove_frame_from_stack(tbss: StackSummary,
                             framename: str) -> StackSummary:
    filtered_stack_list: List[traceback.FrameSummary] = \
        list(filter(lambda frame: getattr(frame,
                                          'filename') != framename, tbss))
    filtered_stack: StackSummary = StackSummary.from_list(filtered_stack_list)
    return filtered_stack
コード例 #3
0
def get_exception_details():
    from traceback import walk_tb, StackSummary, FrameSummary
    from time import strftime
    cla, exc, exc_traceback = sys.exc_info()
    exc_args = exc.__dict__["args"] if "args" in exc.__dict__ else "<no args>"
    ex_title = cla.__name__ + ": Exception:" + str(exc) + " - args:" + str(
        exc_args)
    msgs = [
        ex_title,
    ]
    except_location = ""
    tb: list[FrameSummary] = StackSummary.extract(walk_tb(exc_traceback),
                                                  limit=None,
                                                  capture_locals=True)
    for frame in tb:
        local_vars_info = []
        if frame.locals:
            for name, value in frame.locals.items():
                if name == "self":
                    continue
                local_vars_info.append(f'\t{name} = {value}')
        except_location += "\n" + frame.filename + ":" + str(frame.lineno) + " \n" + str(frame.name) + \
                           "\n<Args>:" + "\n".join(local_vars_info)
    msgs.insert(1, except_location)
    time = strftime("%Y-%m-%d %H:%M:%S")
    return time + " - " + ("".join(msgs))
コード例 #4
0
def iter_traceback(tb=None, enforce_most_recent_call_first=False):
    """
    Iterates a traceback of various formats:
      - traceback (types.TracebackType)
      - frame object (types.FrameType)
      - stack summary (traceback.StackSummary)

    :param types.TracebackType|types.FrameType|StackSummary|None tb: traceback. if None, will use sys._getframe
    :param bool enforce_most_recent_call_first:
        Frame or stack summery: most recent call first (top of the stack is the first entry in the result)
        Traceback: most recent call last
        If True, and we get traceback, will unroll and reverse, such that we have always the most recent call first.
    :return: yields the frames (types.FrameType)
    :rtype: list[types.FrameType|DummyFrame]
    """
    if tb is None:
        tb = get_current_frame()

    def is_stack_summary(_tb):
        return isinstance(_tb, StackSummary)

    is_frame = inspect.isframe
    is_traceback = inspect.istraceback
    assert is_traceback(tb) or is_frame(tb) or is_stack_summary(tb)
    # Frame or stack summery: most recent call first
    # Traceback: most recent call last
    if is_traceback(tb) and enforce_most_recent_call_first:
        frames = list(iter_traceback(tb))
        for frame in frames[::-1]:
            yield frame
        return

    _tb = tb
    while _tb is not None:
        if is_frame(_tb):
            frame = _tb
        elif is_stack_summary(_tb):
            if isinstance(_tb[0], ExtendedFrameSummary):
                frame = _tb[0].tb_frame
            else:
                frame = DummyFrame.from_frame_summary(_tb[0])
        else:
            frame = _tb.tb_frame
        yield frame
        if is_frame(_tb):
            _tb = _tb.f_back
        elif is_stack_summary(_tb):
            _tb = StackSummary.from_list(_tb[1:])
            if not _tb:
                _tb = None
        else:
            _tb = _tb.tb_next
コード例 #5
0
ファイル: main.py プロジェクト: sthagen/typer
def except_hook(
    exc_type: Type[BaseException], exc_value: BaseException, tb: TracebackType
) -> None:
    exception_config: Union[DeveloperExceptionConfig, None] = getattr(
        exc_value, _typer_developer_exception_attr_name, None
    )
    standard_traceback = os.getenv("_TYPER_STANDARD_TRACEBACK")
    if (
        standard_traceback
        or not exception_config
        or not exception_config.pretty_exceptions_enable
    ):
        _original_except_hook(exc_type, exc_value, tb)
        return
    typer_path = os.path.dirname(__file__)
    click_path = os.path.dirname(click.__file__)
    supress_internal_dir_names = [typer_path, click_path]
    exc = exc_value
    if rich:
        rich_tb = Traceback.from_exception(
            type(exc),
            exc,
            exc.__traceback__,
            show_locals=exception_config.pretty_exceptions_show_locals,
            suppress=supress_internal_dir_names,
        )
        console_stderr.print(rich_tb)
        return
    tb_exc = traceback.TracebackException.from_exception(exc)
    stack: List[FrameSummary] = []
    for frame in tb_exc.stack:
        if any(
            [frame.filename.startswith(path) for path in supress_internal_dir_names]
        ):
            if not exception_config.pretty_exceptions_short:
                # Hide the line for internal libraries, Typer and Click
                stack.append(
                    traceback.FrameSummary(
                        filename=frame.filename,
                        lineno=frame.lineno,
                        name=frame.name,
                        line="",
                    )
                )
        else:
            stack.append(frame)
    # Type ignore ref: https://github.com/python/typeshed/pull/8244
    final_stack_summary = StackSummary.from_list(stack)  # type: ignore
    tb_exc.stack = final_stack_summary
    for line in tb_exc.format():
        print(line, file=sys.stderr)
    return
コード例 #6
0
 def __post_init__(self, function, test_id):
     file_frame = FrameSummary(
         inspect.getfile(function),
         docs_start_lineno(function) + self.path.line,
         function.__name__,
         lookup_line=False,
     )
     dynamic_frame = FrameSummary(test_id,
                                  1,
                                  function.__name__,
                                  lookup_line=False,
                                  line=self.path)
     self.stack = StackSummary.from_list([file_frame, dynamic_frame])
コード例 #7
0
ファイル: better_exchook.py プロジェクト: albertz/playground
def _StackSummary_extract(frame_gen, limit=None, lookup_lines=True, capture_locals=False):
    """Create a StackSummary from a traceback or stack object.
    Very simplified copy of the original StackSummary.extract().
    We want always to capture locals, that is why we overwrite it.
    Additionally, we also capture the frame.
    This is a bit hacky and also not like this is originally intended (to not keep refs).

    :param frame_gen: A generator that yields (frame, lineno) tuples to
        include in the stack.
    :param limit: None to include all frames or the number of frames to
        include.
    :param lookup_lines: If True, lookup lines for each frame immediately,
        otherwise lookup is deferred until the frame is rendered.
    :param capture_locals: If True, the local variables from each frame will
        be captured as object representations into the FrameSummary.
    """
    result = StackSummary()
    for f, lineno in frame_gen:
        co = f.f_code
        filename = co.co_filename
        name = co.co_name
        result.append(ExtendedFrameSummary(
            frame=f, filename=filename, lineno=lineno, name=name, lookup_line=False))
    return result
コード例 #8
0
def print_task_stack(task: asyncio.Task,
                     *,
                     file: IO = sys.stderr,
                     limit: int = DEFAULT_MAX_FRAMES,
                     capture_locals: bool = False) -> None:
    """Print the stack trace for an :class:`asyncio.Task`."""
    print(f'Stack for {task!r} (most recent call last):', file=file)
    tb = Traceback.from_task(task, limit=limit)
    print_list(
        StackSummary.extract(
            cast(Generator, walk_tb(cast(TracebackType, tb))),
            limit=limit,
            capture_locals=capture_locals,
        ),
        file=file,
    )
コード例 #9
0
def print_coro_stack(coro: Coroutine,
                     *,
                     file: IO = sys.stderr,
                     limit: int = DEFAULT_MAX_FRAMES,
                     capture_locals: bool = False) -> None:
    """Print the stack trace for a currently running coroutine."""
    print(f'Stack for {coro!r} (most recent call last):', file=file)
    tb = Traceback.from_coroutine(coro, limit=limit)
    print_list(
        StackSummary.extract(
            cast(Generator, walk_tb(cast(TracebackType, tb))),
            limit=limit,
            capture_locals=capture_locals,
        ),
        file=file,
    )
コード例 #10
0
def print_agen_stack(agen: AsyncGenerator,
                     *,
                     file: IO = sys.stderr,
                     limit: int = DEFAULT_MAX_FRAMES,
                     capture_locals: bool = False) -> None:
    """Print the stack trace for a currently running async generator."""
    print(f'Stack for {agen!r} (most recent call last):', file=file)
    tb = Traceback.from_agen(agen, limit=limit)
    print_list(
        StackSummary.extract(
            cast(Generator, walk_tb(cast(TracebackType, tb))),
            limit=limit,
            capture_locals=capture_locals,
        ),
        file=file,
    )
コード例 #11
0
ファイル: tournament.py プロジェクト: owenmackwood/connn
def generate_move_process(generate_move: cu.GenMove, moves_q: mp.Queue):
    from traceback import StackSummary
    from random import seed as random_seed
    import io
    from time import time
    import pickle
    from contextlib import redirect_stderr, redirect_stdout

    logger = logging.getLogger(__name__)
    f_stderr, f_stdout = io.StringIO(), io.StringIO()

    gma: GenMoveArgs = moves_q.get()
    np.random.seed(gma.seed)
    random_seed(gma.seed)

    try:
        with redirect_stdout(f_stdout), redirect_stderr(f_stderr):
            t0 = time()
            returned = generate_move(gma.board, gma.player, gma.state)
            saved_state = None
            if isinstance(returned, tuple):
                action = returned[0]
                if len(returned) > 1:
                    saved_state = returned[1]
            else:
                action = returned

            move_time = time() - t0
        stdout, stderr = f_stdout.getvalue(), f_stderr.getvalue()
        result = GenMoveSuccess(stdout, stderr, move_time, action, saved_state)
    except Exception as e:
        logger.exception("An exception was thrown by the agent.")
        error_msg = repr(e) + "\n"
        extracted_list = traceback.extract_tb(e.__traceback__)
        for item in StackSummary.from_list(extracted_list).format():
            error_msg += str(item)
        stdout, stderr = f_stdout.getvalue(), f_stderr.getvalue()
        result = GenMoveFailure(stdout, stderr, error_msg)

    try:
        moves_q.put(result)
    except pickle.PickleError:
        logger.exception(
            "Internal error in trying to send the result, probably caused by saved_state"
        )
        moves_q.put(GenMoveSuccess(stdout, stderr, move_time, action, None))
コード例 #12
0
ファイル: coord.py プロジェクト: pastly/flashflow
def _exception_handler(loop, context):
    ''' Last resort exception handler

    This will only catch exceptions that happen in the main thread. Others very
    well may go entirely unnoticed and unlogged.

    Some exceptions are unexpected, so we end up here. For these we kill
    ourselves after logging about the exception.

    Other exceptions are impossible to catch before we get here. For example, a
    client failing the TLS handshake with us. (ugh what the f**k). For these we
    notify the state machine so it can react.
    '''
    # Check for exceptions that should not be fatal and we should tell other
    # parts of the code about so they can react intelligently
    if 'exception' in context:
        exception_type = type(context['exception'])
        # Check for recoverable TLS errors
        if exception_type == ssl.SSLError:
            if 'transport' in context:
                machine.notif_sslerror(context['exception'],
                                       context['transport'])
                return
            else:
                log.warn(
                    'SSLError caught without a transport too. Cannot pass ' +
                    'to state machine to handle gracefully.')
        # Additional recoverable errors would continue here
    # All other exceptions. These are fatal
    log.error('%s', context['message'])
    if 'exception' in context:
        log.error('%s %s', type(context['exception']), context['exception'])
    if 'handle' in context:
        log.error(context['handle'])
    if 'source_traceback' in context:
        log.error('Traceback:')
        summary = StackSummary.from_list(context['source_traceback'])
        for line_super in summary.format():
            # The above line has multiple lines in it
            for line in line_super.split('\n'):
                if len(line):
                    log.error('  %s', line)
    else:
        log.error(
            'Traceback not available. Maybe run with PYTHONASYNCIODEBUG=1')
    machine.change_state_fatal_error()
コード例 #13
0
ファイル: measurer.py プロジェクト: pastly/flashflow
def _exception_handler(loop, context):
    log.error('%s', context['message'])
    if 'exception' in context:
        log.error(context['exception'])
    if 'handle' in context:
        log.error(context['handle'])
    if 'source_traceback' in context:
        log.error('Traceback:')
        summary = StackSummary.from_list(context['source_traceback'])
        for line_super in summary.format():
            # The above line has multiple lines in it
            for line in line_super.split('\n'):
                if len(line):
                    log.error('  %s', line)
    else:
        log.error('Traceback not available. Run with PYTHONASYNCIODEBUG=1')
    machine.change_state_fatal_error()
コード例 #14
0
    def format(self, record) -> str:

        # set for different levels
        format_orig = self._style._fmt
        self._style._fmt = self.msg_fmt[record.levelname]

        # preprocess \n
        line_count = 0
        for s in record.msg:
            if s == '\n':
                line_count += 1
                record.msg = record.msg[1:]
            else:
                break
        if record.msg:
            self._style._fmt = line_count * '\n' + self._style._fmt
        else:
            self._style._fmt = line_count * '\n'

        if record.levelno >= self.stack_level and record.levelno != logging.MAIL and record.msg[:
                                                                                                9] != 'Traceback':
            record.stack_info = ''.join(
                StackSummary.from_list(
                    extract_stack()
                    [:self._stack_prune]).format())  # self._stack_prune

        # make it colorful
        levelname = record.levelname
        if self.use_color and levelname in COLORS:
            levelname_color = COLOR_SEQ % (
                30 + COLORS[levelname]) + record.levelname + RESET_SEQ
            record.levelname = levelname_color

        self.datefmt = '%m/%d/%Y %I:%M:%S %p'
        result = logging.Formatter.format(self, record)

        self._style._fmt = format_orig
        record.levelname = levelname

        return result
コード例 #15
0
def format_exc(name='mlchain', tb=None, exception=None):
    if exception is None:
        formatted_lines = traceback.format_exc().splitlines()
    else:
        formatted_lines = []
        if tb is not None:
            for item in StackSummary.from_list(extract_tb(tb)).format():
                str_item = str(item)
                if str_item.endswith("\n"):
                    formatted_lines.append(str_item[:-1])
                else:
                    formatted_lines.append(str_item)
        formatted_lines += [
            x for x in re.split('(\\\\n)|(\\n)', str(exception))
            if x not in ["\\n", "\n", "", None]
        ]

    output = []
    kt = True
    last_mlchain_append = -1
    for x in formatted_lines:
        output.append(x)
        # if x.strip().startswith("File"):
        #     if ('site-packages/mlchain' in x or 'site-packages/trio' in x) and not ("mlchain.base.exceptions" in x or "AssertionError" in x):
        #         kt = False
        #     else:
        #         kt = True

        # if kt or 'AssertionError' in x or 'mlchain.base.exceptions' in x:
        #     if x.startswith("'), AssertionError"):
        #         output.append("\n" + x[4:])
        #     else:
        #         output.append(x)
        # elif last_mlchain_append != len(output):
        #     output.append('  File "{}" collapsed errors'.format(name))
        #     last_mlchain_append = len(output)

    return "\n".join(output) + "\n"
コード例 #16
0
ファイル: log.py プロジェクト: dd-dos/mlchain-python
def format_exc(name='mlchain', tb=None, exception=None, return_str=True):
    if exception is None:
        formatted_lines = traceback.format_exc().splitlines()
    else:
        formatted_lines = []
        if tb is not None:
            for item in StackSummary.from_list(extract_tb(tb)).format():
                str_item = str(item)
                if str_item.endswith("\n"):
                    formatted_lines.append(str_item[:-1])
                else:
                    formatted_lines.append(str_item)
        formatted_lines += [
            x for x in re.split('(\\\\n)|(\\n)', str(exception))
            if x not in ["\\n", "\n", "", None]
        ]

    output = []
    for x in formatted_lines:
        output.append(x)

    if return_str:
        return "\n".join(output)
    return output
コード例 #17
0
ファイル: inspector.py プロジェクト: Dragon2fly/logger_tt
def analyze_frame(trace_back, full_context: int = False) -> str:
    """
    Read out variables' content surrounding the error line of code

    :param trace_back: A traceback object when exception occur
    :param full_context: Also export local variables that is not in the error line
            full_context == 0: export only variables that appear on the error line
            full_context == 1: export variables within the error function's scope
            full_context >= 2: export variables along the function's call stack up to `full_context` level
    :return: string of analyzed frame
    """
    result = []
    full_context = max(0, int(full_context))
    # todo: add color
    bullet_1 = '|->'
    bullet_2 = '=>'
    multi_line_indent1 = 8 + len(bullet_1)
    multi_line_indent2 = 8 + len(bullet_2)
    stack_depth = get_traceback_depth(trace_back)

    with logging_disabled():
        for idx, obj in enumerate(walk_tb(trace_back)):
            frame, _ = obj

            global_var = frame.f_globals
            local_var = frame.f_locals

            summary = StackSummary.extract([obj], capture_locals=True)[0]
            line = summary.line
            if not is_full_statement(summary.line):
                line = get_full_statement(summary.filename, summary.lineno)
                line = '    '.join(line)

            txt = [
                f'  File "{summary.filename}", line {summary.lineno}, in {summary.name}',
                f'    {line}'
            ]

            # todo: dump all level to different file?
            parse_level = max(full_context - 1, 0)
            if idx + 1 < (stack_depth - parse_level):
                # don't parse variables for top levels
                txt.append('')
                result.append('\n'.join(txt))
                continue

            # get value of variables on the error line
            identifiers = ID_PATTERN.findall(line)
            seen = set()
            outer = "(outer) " if idx else ""  # ground level variables are not outer for sure
            for i in identifiers:
                if i in seen or i.endswith('.'):
                    continue

                seen.add(i)
                spaces = multi_line_indent1 + len(i)
                if i in local_var:
                    value = get_repr(local_var[i], spaces)
                    txt.append(f'     {bullet_1} {i} = {value}')
                elif i in global_var:
                    spaces += len(outer)
                    value = get_repr(global_var[i], spaces)
                    txt.append(f'     {bullet_1} {outer}{i} = {value}')
                elif '.' in i:
                    # class attribute access
                    spaces += len(outer)
                    instance = i.split('.')[0]
                    obj = local_var.get(instance, global_var.get(instance))
                    attribute = get_recur_attr(obj, i[len(instance) + 1:])
                    value = get_repr(attribute, spaces)
                    scope = outer if instance in global_var else ''
                    txt.append(f'     {bullet_1} {scope}{i} = {value}')
                else:
                    # reserved Keyword or non-identifier, eg. word inside the string
                    pass

            # get value of other variables within local scope
            if full_context:
                other_local_var = set(local_var) - set(identifiers)
                if other_local_var:
                    spaces = multi_line_indent2
                    txt.extend([
                        f'     {bullet_2} {k} = {get_repr(v, spaces + len(k))}'
                        for k, v in local_var.items() if k in other_local_var
                    ])

            txt.append('')
            result.append('\n'.join(txt))

    return '\n'.join(result)
コード例 #18
0
ファイル: api.py プロジェクト: N-Coder/mensabot
 def dump_stack(frames):
     stack = StackSummary.from_list(extract_stack(frames))
     return [{"filename": f.filename, "lineno": f.lineno, "name": f.name, "line": f.line,
              "locals": {name: repr(value) for name, value in sorted(f.locals.items())} if f.locals else None}
             for f in stack]
コード例 #19
0
from contextlib import suppress

# External
from async_tools import Loopable
from async_tools.abstract import Loopable as AbstractLoopable

# Project
from ._helper import reject, fulfill, resolve

# Generic types
K = T.TypeVar("K")
L = T.TypeVar("L")

# Fake stacktrace information for use when no stack can be recovered from promise
_FAKE_STACK = list(
    StackSummary.from_list([("unknown", 0, "unknown", "invalid")]))


class ChainLink(T.Awaitable[K], Loopable):
    @staticmethod
    def log_unhandled_exception(promise: "ChainLink[T.Any]",
                                fut: "Future[T.Any]") -> None:
        assert fut.done()

        get_loop: T.Callable[[], AbstractEventLoop] = getattr(
            fut, "get_loop", None)
        loop: AbstractEventLoop = get_loop() if callable(
            get_loop) else getattr(fut, "_loop", None)

        assert loop is not None
コード例 #20
0
def extract_log_tb(exc=None):
    tb = ''.join(StackSummary.extract(walk_tb(sys.exc_info()[-1])).format())
    if exc.__cause__ is not None and isinstance(exc.__cause__, Traceback):
        tb = exc.__cause__.tb + tb
    return tb
コード例 #21
0
ファイル: views.py プロジェクト: inhzus/berater
def handle_exceptions(err: Exception):
    msg = '\n'.join(['', ''.join(StackSummary.from_list(extract_tb(err.__traceback__)).format()), repr(err)])
    current_app.logger.error(msg)
    return jsonify(code=500, error=repr(err), data=None), 200
コード例 #22
0
def format_tb(tb=None, limit=None, allLocals=None, allGlobals=None, withTitle=False, with_color=None, with_vars=None):
    """
    :param types.TracebackType|types.FrameType|StackSummary tb: traceback. if None, will use sys._getframe
    :param int|None limit: limit the traceback to this number of frames. by default, will look at sys.tracebacklimit
    :param dict[str]|None allLocals: if set, will update it with all locals from all frames
    :param dict[str]|None allGlobals: if set, will update it with all globals from all frames
    :param bool withTitle:
    :param bool|None with_color: output with ANSI escape codes for color
    :param bool with_vars: will print var content which are referenced in the source code line. by default enabled.
    :return: list of strings (line-based)
    :rtype: list[str]
    """
    if with_vars is None and is_at_exit():
        # Better to not show __repr__ of some vars, as this might lead to crashes
        # when native extensions are involved.
        with_vars = False
    if with_vars is None:
        if any([f.f_code.co_name == "__del__" for f in iter_traceback()]):
            # __del__ is usually called via the Python garbage collector (GC).
            # This can happen and very random / non-deterministic places.
            # There are cases where it is not safe to access some of the vars on the stack
            # because they might be in a non-well-defined state, thus calling their __repr__ is not safe.
            # See e.g. this bug:
            # https://github.com/tensorflow/tensorflow/issues/22770
            with_vars = False
    if with_vars is None:
        with_vars = True
    color = Color(enable=with_color)
    out = []
    def output(s1, s2=None, **kwargs):
        if kwargs:
            s1 = color(s1, **kwargs)
        if s2 is not None:
            s1 = add_indent_lines(s1, s2)
        out.append(s1 + "\n")
    def format_filename(s):
        base = os.path.basename(s)
        return (
            color('"' + s[:-len(base)], "cyan") +
            color(base, "cyan", bold=True) +
            color('"', "cyan"))
    def format_py_obj(obj):
        return color.py_syntax_highlight(pretty_print(obj))
    if tb is None:
        try:
            tb = get_current_frame()
            assert tb
        except Exception:
            output(color("format_tb: tb is None and sys._getframe() failed", "red", bold=True))
            return out
    def isstacksummary(_tb):
        return isinstance(_tb, StackSummary)
    isframe = inspect.isframe
    if withTitle:
        if isframe(tb) or isstacksummary(tb):
            output(color('Traceback (most recent call first):', "blue"))
        else:  # expect traceback-object (or compatible)
            output(color('Traceback (most recent call last):', "blue"))
    try:
        if limit is None:
            if hasattr(sys, 'tracebacklimit'):
                limit = sys.tracebacklimit
        n = 0
        _tb = tb
        class NotFound(Exception):
            pass
        def _resolve_identifier(namespace, id):
            if id[0] not in namespace:
                raise NotFound()
            obj = namespace[id[0]]
            for part in id[1:]:
                obj = getattr(obj, part)
            return obj
        def _try_set(old, prefix, func):
            if old is not None: return old
            try: return add_indent_lines(prefix, func())
            except NotFound: return old
            except Exception as e:
                return prefix + "!" + e.__class__.__name__ + ": " + str(e)
        while _tb is not None and (limit is None or n < limit):
            if isframe(_tb):
                f = _tb
            elif isstacksummary(_tb):
                if isinstance(_tb[0], ExtendedFrameSummary):
                    f = _tb[0].tb_frame
                else:
                    f = DummyFrame.from_frame_summary(_tb[0])
            else:
                f = _tb.tb_frame
            if allLocals is not None: allLocals.update(f.f_locals)
            if allGlobals is not None: allGlobals.update(f.f_globals)
            if hasattr(_tb, "tb_lineno"): lineno = _tb.tb_lineno
            elif isstacksummary(_tb): lineno = _tb[0].lineno
            else: lineno = f.f_lineno
            co = f.f_code
            filename = co.co_filename
            name = co.co_name
            output("".join([
                '  ',
                color("File ", "blue", bold=True), format_filename(filename), ", ",
                color("line ", "blue"), color("%d" % lineno, "magenta"), ", ",
                color("in ", "blue"), name]))
            if not os.path.isfile(filename):
                altfn = fallback_findfile(filename)
                if altfn:
                    output(color("    -- couldn't find file, trying this instead: ", "blue") +
                           format_filename(altfn))
                    filename = altfn
            source_code = get_source_code(filename, lineno, f.f_globals)
            if source_code:
                source_code = remove_indent_lines(replace_tab_indents(source_code)).rstrip()
                output("    line: ", color.py_syntax_highlight(source_code), color="blue")
                if not with_vars:
                    pass
                elif isinstance(f, DummyFrame) and not f.have_vars_available:
                    pass
                else:
                    output(color('    locals:', "blue"))
                    alreadyPrintedLocals = set()
                    for tokenstr in grep_full_py_identifiers(parse_py_statement(source_code)):
                        splittedtoken = tuple(tokenstr.split("."))
                        for token in [splittedtoken[0:i] for i in range(1, len(splittedtoken) + 1)]:
                            if token in alreadyPrintedLocals: continue
                            tokenvalue = None
                            tokenvalue = _try_set(tokenvalue, color("<local> ", "blue"), lambda: format_py_obj(_resolve_identifier(f.f_locals, token)))
                            tokenvalue = _try_set(tokenvalue, color("<global> ", "blue"), lambda: format_py_obj(_resolve_identifier(f.f_globals, token)))
                            tokenvalue = _try_set(tokenvalue, color("<builtin> ", "blue"), lambda: format_py_obj(_resolve_identifier(f.f_builtins, token)))
                            tokenvalue = tokenvalue or color("<not found>", "blue")
                            prefix = '      %s ' % color(".", "blue", bold=True).join(token) + color("= ", "blue", bold=True)
                            output(prefix, tokenvalue)
                            alreadyPrintedLocals.add(token)
                    if len(alreadyPrintedLocals) == 0:
                        output(color("       no locals", "blue"))
            else:
                output(color('    -- code not available --', "blue"))
            if isframe(_tb):
                _tb = _tb.f_back
            elif isstacksummary(_tb):
                _tb = StackSummary.from_list(_tb[1:])
                if not _tb:
                    _tb = None
            else:
                _tb = _tb.tb_next
            n += 1

    except Exception as e:
        output(color("ERROR: cannot get more detailed exception info because:", "red", bold=True))
        import traceback
        for l in traceback.format_exc().split("\n"):
            output("   " + l)

    return out