Files
controller-wisetopdataserver/python/biopro/util/_stack.py
T
2021-12-20 14:52:55 +08:00

154 lines
3.7 KiB
Python

"""implement of stack.py"""
import inspect
import os
import os.path
import sys
import threading as _threading
from typing import Optional
from .console import pc, WHITE, RED, YELLOW
from .logger import Logger
_RUNTIME_COMPILE = False
if _RUNTIME_COMPILE:
raise RuntimeError()
try:
_TRACE_LEVEL = int(os.getenv('TRACE_LEVEL', 1))
'''
0 : print nothing
1 : print last stack
2 : print all stack
'''
except ValueError:
_TRACE_LEVEL = 1
try:
_TRACE_CONTEXT = int(os.getenv('TRACE_CONTEXT', 5))
except ValueError:
_TRACE_CONTEXT = 5
_LOCK = _threading.RLock()
def print_exception(logger: Optional[Logger] = None,
exc_info=None,
reverse_order=True):
if exc_info is None:
e_class, e_value, e_stack = sys.exc_info()
else:
e_class, e_value, e_stack = exc_info
if logger is None:
print(pc(e_class.__name__, YELLOW), ':', pc(e_value, WHITE))
else:
logger.log_error(pc(e_class.__name__, YELLOW), ':', pc(e_value, WHITE))
if _TRACE_LEVEL == 0:
return
trace = inspect.trace(context=_TRACE_CONTEXT)
while e_value.__cause__ is not None:
e_value = e_value.__cause__
e_stack = e_value.__traceback__
trace.extend(inspect.getinnerframes(e_stack, context=_TRACE_CONTEXT))
if _TRACE_LEVEL == 1:
_print_stack_frame(trace[0])
else:
frame = inspect.stack(context=_TRACE_CONTEXT)[2:]
if not reverse_order:
trace = trace[::-1]
trace.extend(frame)
else:
frame = frame[::-1]
frame.extend(trace)
trace = frame
for f in trace:
_print_stack_frame(f)
def print_stack(reverse_order=True):
if _TRACE_LEVEL == 0:
return
frame = inspect.stack(context=_TRACE_CONTEXT)[1:]
if _TRACE_LEVEL == 1:
_print_stack_frame(frame[0])
else:
if reverse_order:
frame = reversed(frame)
for f in frame:
_print_stack_frame(f)
def _print_stack_frame(f: inspect.FrameInfo):
file_path = f.filename
file_dir = os.path.dirname(file_path)
file_name = os.path.basename(file_path)
cls_name = _get_class_name(file_path, f.lineno)
with _LOCK:
if cls_name is None:
print(' ',
file_dir + ' ' + pc(file_name, WHITE) + ':' + str(f.lineno),
pc(f.function, RED))
else:
print(' ',
file_dir + ' ' + pc(file_name, WHITE) + ':' + str(f.lineno),
pc(cls_name, YELLOW) + '.' + pc(f.function, RED))
if f.index is not None:
offset = -f.index
for i, content in enumerate(f.code_context):
line_number = f.lineno + offset + i
if line_number == f.lineno:
print(pc(' %4d %s' % (line_number, content.rstrip()), WHITE))
else:
print(' %4d' % line_number, content.rstrip())
print()
def _get_class_name(filepath: str, line_number: int) -> Optional[str]:
class_name = None
try:
with open(filepath) as f:
for ln, line in enumerate(f): # type: (int, str)
if ln + 1 == line_number:
break
line = line.strip()
if line.startswith('class '):
i = line.index(' ')
try:
j = line.index('(')
except ValueError:
try:
j = line.index(':')
except ValueError:
j = len(line)
class_name = line[i + 1:j]
except FileNotFoundError:
pass
return class_name