mower-ng/mower/utils/traceback.py
2024-11-06 23:46:23 +08:00

78 lines
2.5 KiB
Python

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():
"""日志前缀
利用调用栈的信息找出打印日志的代码来自哪里。
类名的获取:
1. 如果类存在solver_name属性,返回这个Solver的名字。如果solver_name为None,使用qualname替代;
2. 如果没有被Solver调用,返回调用栈最内层的类。
"""
# 遍历调用栈,记录最内层的类,并寻找Solver类。找到Solver类后返回;没有Solver类则返回最内层的类。
caller_class = None # 记录最内层的类
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__ # 不是类的会触发异常
qualname = caller.__qualname__
if caller_class is None: # 更新最内层的类
caller_class = qualname
name = caller.solver_name # 不是Solver的类会触发异常
return name or qualname, relative_path, func_name, lineno
except Exception:
pass
return caller_class, relative_path, func_name, lineno
def log_debug():
stack_info = fast_stack(3)[2]
func_name = stack_info.function
lineno = stack_info.lineno
relative_path = Path(stack_info.filename)
try:
relative_path = relative_path.relative_to(get_path("@install"))
except ValueError:
pass
return relative_path, func_name, lineno