import inspect import itertools from pathlib import Path from types import FrameType from mower.utils.path import get_path # https://stackoverflow.com/a/78770438 def fast_stack(max_depth: int | None = None): def frame_infos(frame: FrameType | None): while frame := frame and frame.f_back: yield inspect.FrameInfo( frame, inspect.getfile(frame), frame.f_lineno, frame.f_code.co_name, None, None, ) return list(itertools.islice(frame_infos(inspect.currentframe()), max_depth)) def caller_info(): caller = fast_stack(3)[2] relative_path = Path(caller.filename) try: relative_path = relative_path.relative_to(get_path("@install")) except ValueError: pass return f"{relative_path}:{caller.lineno}" def log_info(): caller_class = [] tmp_class = [] stack_info = fast_stack() func_name = stack_info[2].function lineno = stack_info[2].lineno relative_path = Path(stack_info[2].filename) try: relative_path = relative_path.relative_to(get_path("@install")) except ValueError: pass for st in stack_info[2:]: try: caller = st.frame.f_locals["self"].__class__ except Exception: continue try: name = caller.solver_name solver = True except Exception: name = caller.__qualname__ solver = False if name is None: continue tmp_class.insert(0, name) if solver: caller_class = tmp_class + caller_class tmp_class = [] caller_class = "|".join([key for key, _ in itertools.groupby(caller_class)]) return (caller_class, relative_path, func_name, lineno)