I was incredibly annoyed by this problem and eventually wrote a library to solve it: decopatch .
It supports two development styles: nested (as in Python decorator factories) and flat (one level less than nesting). Here's how your example will be implemented in flat mode:
from decopatch import function_decorator, DECORATED from makefun import wraps @function_decorator def foo_register(method_name=None, method=DECORATED): if method_name is None: method.gw_method = method.__name__ else: method.gw_method = method_name
Note that I use makefun.wraps instead of functools.wraps here so that the signature is fully preserved (the shell is not called at all if the arguments are invalid).
decopatch supports an additional development style, which I call double-flat , which is designed to create shells with a signature-saving function like this. Your example will be implemented like this:
from decopatch import function_decorator, WRAPPED, F_ARGS, F_KWARGS @function_decorator def foo_register(method_name=None, method=WRAPPED, f_args=F_ARGS, f_kwargs=F_KWARGS): # this is directly the wrapper if method_name is None: method.gw_method = method.__name__ else: method.gw_method = method_name method(*f_args, **f_kwargs)
Note that in this style, all your code is executed in method calls. This may not be desirable - you may want to do things only once during the decoration - the previous style will be better for this.
You can verify that both styles work:
@foo_register def my_function(): print('hi...') @foo_register('say_hi') def my_function(): print('hi...')
Please check the documentation for details.
smarie Mar 11 '19 at 17:20 2019-03-11 17:20
source share