116 lines
3.4 KiB
Python
116 lines
3.4 KiB
Python
import inspect
|
|
from opcode import opname
|
|
from collections import defaultdict
|
|
|
|
|
|
def get_var_name(frame):
|
|
code = frame.f_code
|
|
call_index = frame.f_lasti
|
|
call_opc = opname[code.co_code[call_index]]
|
|
if call_opc != "CALL_FUNCTION" and call_opc != "CALL_FUNCTION_VAR":
|
|
return None
|
|
index = call_index+3
|
|
while True:
|
|
opc = opname[code.co_code[index]]
|
|
if opc == "STORE_NAME" or opc == "STORE_ATTR":
|
|
name_index = int(code.co_code[index+1])
|
|
return code.co_names[name_index]
|
|
elif opc == "STORE_FAST":
|
|
name_index = int(code.co_code[index+1])
|
|
return code.co_varnames[name_index]
|
|
elif opc == "STORE_DEREF":
|
|
name_index = int(code.co_code[index+1])
|
|
return code.co_cellvars[name_index]
|
|
elif opc == "LOAD_GLOBAL" or opc == "LOAD_ATTR" or opc == "LOAD_FAST" or opc == "LOAD_DEREF":
|
|
index += 3
|
|
elif opc == "DUP_TOP":
|
|
index += 1
|
|
elif opc == "BUILD_LIST":
|
|
index += 3
|
|
else:
|
|
return None
|
|
|
|
|
|
def remove_underscore(s):
|
|
if len(s) > 2 and s[0] == "_" and s[1] != "_":
|
|
s = s[1:]
|
|
return s
|
|
|
|
|
|
def get_obj_var_name(override=None, default=None):
|
|
if override:
|
|
return override
|
|
|
|
frame = inspect.currentframe().f_back
|
|
# We can be called via derived classes. Go back the stack frames
|
|
# until we reach the first class that does not inherit from us.
|
|
ourclass = frame.f_locals["self"].__class__
|
|
while "self" in frame.f_locals and isinstance(frame.f_locals["self"], ourclass):
|
|
frame = frame.f_back
|
|
|
|
vn = get_var_name(frame)
|
|
if vn is None:
|
|
vn = default
|
|
else:
|
|
vn = remove_underscore(vn)
|
|
return vn
|
|
|
|
name_to_idx = defaultdict(int)
|
|
classname_to_objs = dict()
|
|
|
|
|
|
def index_id(l, obj):
|
|
for n, e in enumerate(l):
|
|
if id(e) == id(obj):
|
|
return n
|
|
raise ValueError
|
|
|
|
|
|
def trace_back(varname=None):
|
|
l = []
|
|
frame = inspect.currentframe().f_back.f_back
|
|
while frame is not None:
|
|
if varname is None:
|
|
varname = get_var_name(frame)
|
|
if varname is not None:
|
|
varname = remove_underscore(varname)
|
|
l.insert(0, (varname, name_to_idx[varname]))
|
|
name_to_idx[varname] += 1
|
|
|
|
try:
|
|
obj = frame.f_locals["self"]
|
|
except KeyError:
|
|
obj = None
|
|
if hasattr(obj, "__del__"):
|
|
obj = None
|
|
|
|
if obj is None:
|
|
if varname is not None:
|
|
coname = frame.f_code.co_name
|
|
if coname == "<module>":
|
|
modules = frame.f_globals["__name__"]
|
|
modules = modules.split(".")
|
|
coname = modules[len(modules)-1]
|
|
coname = remove_underscore(coname)
|
|
l.insert(0, (coname, name_to_idx[coname]))
|
|
name_to_idx[coname] += 1
|
|
else:
|
|
classname = obj.__class__.__name__.lower()
|
|
try:
|
|
objs = classname_to_objs[classname]
|
|
except KeyError:
|
|
classname_to_objs[classname] = [obj]
|
|
idx = 0
|
|
else:
|
|
try:
|
|
idx = index_id(objs, obj)
|
|
except ValueError:
|
|
idx = len(objs)
|
|
objs.append(obj)
|
|
classname = remove_underscore(classname)
|
|
l.insert(0, (classname, idx))
|
|
|
|
varname = None
|
|
frame = frame.f_back
|
|
return l
|