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