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 == "": 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