Source code for ocebuild.errors._lib

## @file
# Copyright (c) 2023, The OCE Build Authors. All rights reserved.
# SPDX-License-Identifier: BSD-3-Clause
##
"""Stacktrace introspection methods used for testing and at runtime."""

import sys
from contextlib import contextmanager
from sys import exc_info
from traceback import extract_tb, print_exception

from types import ModuleType
from typing import List, Optional

from ocebuild import __file__ as module_path

#NOTE: This import was remapped from 'third_party' to 'ocebuild.third_party'.
from ocebuild.third_party.cpython.pathlib import Path


@contextmanager
[docs]def disable_exception_traceback(tracebacklimit: int=0): """Suppresses stack trace information from an exception. Args: tracebacklimit: The number of stack frames to show. Defaults to 0. Example: >>> with disable_exception_traceback(): ... raise Exception('This exception will not show a stack trace.') # -> Exception: This exception will not show a stack trace. """ default_value = sys.__dict__.get('tracebacklimit', 1000) sys.tracebacklimit = tracebacklimit yield sys.tracebacklimit = default_value
[docs]def wrap_exception(suppress: Optional[List[str]]=None, suppress_internal: bool=True, suppress_stdlib: bool=False, hide_modules: Optional[List[ModuleType]]=None, hide_suppressed: bool=True, hide_locals: bool=True, max_frames: int=100, use_rich: bool=False): """Hides internal stackframes with an optional stylized stack trace. Args: suppress: A list of paths to suppress from the stack trace. suppress_internal: Whether to suppress internal frames (default: True). suppress_stdlib: Whether to suppress standard library frames (default: False). hide_modules: A list of modules to hide from the stack trace. hide_suppressed: Whether to hide suppressed frames (default: True). hide_locals: Whether to hide local variables (default: True). max_frames: The maximum number of frames to show (default: 100). use_rich: Whether to use rich to display the stack trace (default: False). Example: >>> try: ... raise Exception('This exception will not show internal frames.') ... except Exception: ... wrap_exception() # -> Exception: This exception will not show internal frames. """ if not suppress: suppress = [] if not hide_modules: hide_modules = [] e_type, e, tb = exc_info() module = str(Path(module_path).parent) hidden_module_paths = \ set(str(Path(m.__file__).parent) for m in hide_modules) tb_frame = tb tb_prev = None prev_frame = None excluded_paths = [__file__, *suppress, *hide_modules] for frame in extract_tb(tb, limit=None): # Stop at the end of the traceback if not tb_frame: break # Don't include hidden modules (if specified) is_hidden_module = \ any(m in frame.filename for m in hidden_module_paths) # Don't include internal frames (if specified) is_internal_frame = \ suppress_internal and frame.name.startswith('_') # Don't include duplicate frames is_duplicate_frame = False if prev_frame: is_duplicate_frame = \ prev_frame.filename == frame.filename and \ prev_frame.lineno == frame.lineno and \ prev_frame.name == frame.name # Prune the traceback linked list if is_hidden_module or is_internal_frame or is_duplicate_frame: if tb_prev: tb_prev.tb_next = None elif suppress_stdlib and not module in (path := frame.filename): excluded_paths.append(path) elif hide_suppressed: if tb_prev: tb_prev.tb_next = tb_frame tb_prev = tb_frame tb_frame = tb_frame.tb_next prev_frame = frame if use_rich: _rich_traceback_omit = True #pylint: disable=invalid-name,unused-variable from rich.console import Console #pylint: disable=import-outside-toplevel Console().print_exception(show_locals=not hide_locals, suppress=excluded_paths, max_frames=max_frames) sys.exit(1) else: print_exception(e_type, e, tb, limit=max_frames, file=sys.stderr)
__all__ = [ # Functions (2) "disable_exception_traceback", "wrap_exception" ]