Get Function Object From Stack (frame) Object
I have written a custom logging class for module logging that I called call. With this class I hope to place it in any function/method and it logs the function name with its argume
Solution 1:
Use getattr(module, codename)
to get the function-object of functions that are not contained in classes.
Here the full code:
import logging
import inspect
defcall(logger):
fname = [] # Function name including module and class
fargs = [] # Arguments of function including positional and named arguments
parentframe = inspect.stack()[1][0]
module = inspect.getmodule(parentframe)
if module and module.__name__ != "__main__":
fname.append(module.__name__)
codename = parentframe.f_code.co_name
if"self"in parentframe.f_locals:
fname.append(parentframe.f_locals["self"].__class__.__name__)
fobj = getattr(parentframe.f_locals["self"].__class__, codename)
else:
fobj = getattr(module, codename)
if codename != "<module>":
fname.append(codename)
argspec = inspect.formatargspec(*inspect.getfullargspec(fobj))
args = argspec[1:-1].split(",")
for arg in args:
argkey = arg.strip().replace("*", "").split("=")[0]
if arg == "self":
fargs.append("self")
else:
fargs.append(arg.split("=")[0] + "=" + str(parentframe.f_locals[argkey]))
del parentframe
msg = ".".join(fname) + "(" + ",".join(fargs) + ")"if logger.isEnabledFor(30):
logger.log(30, msg)
classFoo:
def__init__(self, l):
self.logger = l
defbar(self, a, b, c=3, *args, **kwargs):
call(self.logger)
defboo(a, b, c=3, *args, **kwargs):
call(logger)
if __name__ == "__main__":
logging.addLevelName(30, "CALL")
logger = logging.getLogger('blub')
logger.level = 20
f = Foo(logger)
f.bar(1, 2, something=4)
boo(1, 2, something=4)
print("done...")
Solution 2:
Taking ideas from both, I wrote this function to find the function object from a frame. I'm sure there's some edge cases around inherited staticmethods, and obviously any code not using the cls
and self
conventions for param names. This also doesn't work for lambdas... but you shouldn't be logging anything out in a lamba anyway :-P
def_get_func_obj(f):
"""
Get function object from a frame. If it can't find it, return None
"""
codename = f.f_code.co_name
fobj = Nonetry:
if"self"in f.f_locals: # regular method
fobj = getattr(f.f_locals["self"].__class__, codename)
elif"cls"in f.f_locals: # class method
fobj = getattr(f.f_locals["cls"], codename)
else:
module = inspect.getmodule(f) # only fetch module if we need itifhasattr(module, codename): # regular module level function
fobj = getattr(module, codename)
else: # static method
classes = [
getattr(module, name)
for name indir(module)
if inspect.isclass(getattr(module, name))
]
for cls in classes:
if (
hasattr(cls, codename)
andgetattr(cls, codename).__code__ == f.f_code
):
fobj = getattr(cls, codename)
breakif fobj isNone:
"""it's likely some nested function/method or a lambda, who logs in a lambda?"""return fobj
except Exception:
"""never break logging"""
Post a Comment for "Get Function Object From Stack (frame) Object"