import sys from opcode import opname __all__ = ["NameNotFound", "get_var_name", "get_src_loc"] class NameNotFound(Exception): pass _raise_exception = object() def get_var_name(depth=2, default=_raise_exception): frame = sys._getframe(depth) code = frame.f_code call_index = frame.f_lasti while True: call_opc = opname[code.co_code[call_index]] if call_opc in ("EXTENDED_ARG",): call_index += 2 else: break if call_opc not in ("CALL_FUNCTION", "CALL_FUNCTION_KW", "CALL_FUNCTION_EX", "CALL_METHOD"): return None index = call_index + 2 while True: opc = opname[code.co_code[index]] if opc in ("STORE_NAME", "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 in ("LOAD_GLOBAL", "LOAD_ATTR", "LOAD_FAST", "LOAD_DEREF", "DUP_TOP", "BUILD_LIST"): index += 2 else: if default is _raise_exception: raise NameNotFound else: return default def get_src_loc(src_loc_at=0): # n-th frame: get_src_loc() # n-1th frame: caller of get_src_loc() (usually constructor) # n-2th frame: caller of caller (usually user code) frame = sys._getframe(2 + src_loc_at) return (frame.f_code.co_filename, frame.f_lineno)