Is there any kind of way to get the arguments of a decorator function at run time? The project I'm working on is huge and it would be a huge effort to rewrite the affected code. I need a dynamic solution to list all 'categories' assigned to a list of functions. For this I want to avoid super hacky solutions, like regexing through all my modules. Can this be done by inspecting the frames from the call stack?
In our environment the functions are object methods, and we use chained decorators as well. For the ease of understanding I put together this bit of code.
If this is not possible, I can put together another decorator for parts of the project, although it would add much more complexity. But any suggestion to solve my issue is welcome.
def check(*args):
# do something project relevant, so just return True
return True
def decorate(*categories):
def wrap(f):
def wrap_check_categories(*args, **kwargs):
if check(*categories):
return f(*args, **kwargs)
else:
raise Exception
return wrap_check_categories
return wrap
def get_categories(f):
'''Returns decorator parameters'''
# ... do some magic here
raise NotImplementedError
@decorate('foo', 'bar')
def fancy_func(*args, **kwargs):
return args, kwargs
def main():
## should output ['foo', 'bar']
print get_categories(fancy_func)
if __name__ == '__main__':
main()
Modify the decorator to store the categories in an attribute (e.g. _args
) of the decorated function:
def check(*args):
# do something project relevant, so just return True
return True
def decorate(*categories):
def wrap(f):
def wrap_check_categories(*args, **kwargs):
if check(*categories):
return f(*args, **kwargs)
else:
raise Exception
wrap_check_categories._args = categories # <-- store the categories
return wrap_check_categories
return wrap
def get_categories(f):
'''Returns decorator parameters'''
# ... do some magic here
return f._args
@decorate('foo', 'bar')
def fancy_func(*args, **kwargs):
return args, kwargs
def main():
## should output ['foo', 'bar']
print get_categories(fancy_func)
if __name__ == '__main__':
main()
yields
('foo', 'bar')