Source code for jgdv.debugging.traceback_factory

  1#!/usr/bin/env python3
  2"""
  3
  4"""
  5
  6# Imports:
  7from __future__ import annotations
  8
  9# ##-- stdlib imports
 10import datetime
 11from collections import defaultdict
 12import linecache
 13import enum
 14import functools as ftz
 15import math
 16import itertools as itz
 17import inspect
 18import logging as logmod
 19import gc
 20import re
 21import sys
 22import time
 23import weakref
 24import trace
 25from uuid import UUID, uuid1
 26import pathlib as pl
 27
 28# ##-- end stdlib imports
 29
 30# ##-- types
 31# isort: off
 32# General
 33import abc
 34import collections.abc
 35import typing
 36import types
 37from typing import cast, assert_type, assert_never
 38from typing import Generic, NewType, Never
 39from typing import no_type_check, final, override, overload
 40from typing import Concatenate as Cons
 41# Protocols and Interfaces:
 42from typing import Protocol, runtime_checkable
 43# isort: on
 44# ##-- end types
 45
 46# ##-- type checking
 47# isort: off
 48if typing.TYPE_CHECKING:
 49    from ._interface import TraceEvent
 50    from typing import Final, ClassVar, Any, Self
 51    from typing import Literal, LiteralString
 52    from typing import TypeGuard
 53    from collections.abc import Iterable, Iterator, Callable, Generator
 54    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 55
 56    from jgdv import Maybe, Traceback, Frame
 57## isort: on
 58# ##-- end type checking
 59
 60##-- logging
 61logging = logmod.getLogger(__name__)
 62##-- end logging
 63
 64##-- system guards
 65if not hasattr(sys, "_getframe"):
 66        msg = "Can't use TraceBuilder on this system, there is no sys._getframe"
 67        raise ImportError(msg)
 68##-- end system guards
 69
 70##--|
 71
[docs] 72class TracebackFactory: 73 """ A Helper to simplify access to tracebacks. 74 By Default, removes the frames of this tracebuilder from the trace 75 ie : TraceBuilder._get_frames() -> TraceBuilder.__init__() -> call -> call -> root 76 will be: call -> call -> root 77 78 use item acccess to limit the frames, 79 eg: tb[2:], will remove the two most recent frames from the traceback 80 81 Use as: 82 tb = TraceBuilder() 83 raise Exception().with_traceback(tb[:]) 84 """ 85 86 def __class_getitem__(cls, item:slice) -> Maybe[Traceback]: 87 tbb = cls() 88 return tbb[item] 89 90 def __init__(self, *, chop_self:bool=True) -> None: 91 self.frames : list[Frame] = [] 92 self._get_frames() 93 if chop_self: 94 self.frames = self.frames[2:] 95 96 def __getitem__(self, val:Maybe[slice]=None) -> Maybe[Traceback]: 97 match val: 98 case None: 99 return self.to_tb() 100 case slice() | int(): 101 return self.to_tb(self.frames[val]) 102 case _: 103 msg = "Bad value passed to TraceHelper" 104 raise TypeError(msg, val) 105
[docs] 106 def _get_frames(self) -> None: 107 """ from https://stackoverflow.com/questions/27138440 108 Builds the frame stack from most recent to least, 109 """ 110 depth = 0 111 while True: 112 try: 113 frame : Frame = sys._getframe(depth) 114 depth += 1 115 except ValueError: 116 break 117 else: 118 self.frames.append(frame)
119
[docs] 120 def to_tb(self, frames:Maybe[list[Frame]]=None) -> Maybe[Traceback]: 121 top = None 122 frames = frames or self.frames 123 for frame in frames: 124 top = types.TracebackType(top, frame, 125 frame.f_lasti, 126 frame.f_lineno) 127 else: 128 return top
129