-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How do I create a "signature-changing" decorator with decorator.py? #71
Comments
Yes, you can and you need to use the FunctionMaker class to do that. But there no examples in the docs for that. The function |
I see now. It IS (can acts as) a signature changing decorator. It cannot CREATE signature changing decorators. Now the docs make sense. I'd love for that distinction to be made a little clearer in the docs, and to see a new easy to use function equivalent to While looking into this I discovered |
You may try this project https://github.com/smarie/python-makefun which is based on the decorator module. |
Thanks @micheles for the redirection, yes I think that Here is how you would create your decorator using makefun: from inspect import signature, Parameter
from makefun import wraps, add_signature_parameters
def mydec(func):
"""
A decorator to add 2 keyword arguments to the decorated function.
:param func:
:return:
"""
# add parameters to the wrapped function signature
func_sig = signature(func)
new_kw_param = Parameter('new_kw', kind=Parameter.POSITIONAL_OR_KEYWORD, default=None)
another_new_kw_param = Parameter('another_new_kw', kind=Parameter.POSITIONAL_OR_KEYWORD, default=None)
new_sig = add_signature_parameters(func_sig, last=(new_kw_param, another_new_kw_param))
# create the new function with modified signature
@wraps(func, new_sig=new_sig)
def new_func(*args, **kwargs):
new_kw = kwargs.pop('new_kw')
another_new_kw = kwargs.pop('another_new_kw')
if new_kw:
print(new_kw)
return func(*args, **kwargs)
# return the new function
return new_func
# ------ Test
@mydec
def foo(a):
return a + 1
assert foo(1) == 2
assert foo(1, new_kw='bar') == 2 # prints 'bar'
print(help(foo)) # new signature If you then wish to make the decorator creation step more easy, you can use from inspect import signature, Parameter
from decopatch import function_decorator, DECORATED
from makefun import wraps, add_signature_parameters
@function_decorator
def mydec(func=DECORATED, msg_to_print="hello"):
"""
A decorator to add 2 keyword arguments to the decorated function.
:param msg_to_print: the message to print
:return:
"""
# add parameters to the wrapped function signature
func_sig = signature(func)
new_kw_param = Parameter('new_kw', kind=Parameter.POSITIONAL_OR_KEYWORD, default=None)
another_new_kw_param = Parameter('another_new_kw', kind=Parameter.POSITIONAL_OR_KEYWORD, default=None)
new_sig = add_signature_parameters(func_sig, last=(new_kw_param, another_new_kw_param))
# create the new function with modified signature
@wraps(func, new_sig=new_sig)
def new_func(*args, **kwargs):
new_kw = kwargs.pop('new_kw')
another_new_kw = kwargs.pop('another_new_kw')
if new_kw:
print("%s %s" % (msg_to_print, new_kw))
return func(*args, **kwargs)
# return the new function
return new_func
# ------ Test
@mydec # no parenthesis ! default behaviour
def foo(a):
return a + 1
assert foo(1) == 2
assert foo(1, new_kw='bar') == 2 # prints 'hello bar'
@mydec(msg_to_print="oops")
def foo2(a):
return a + 2
assert foo2(1) == 3
assert foo2(1, new_kw='bar') == 3 # prints 'oops bar' Note: the helper function |
The docs (https://github.com/micheles/decorator/blob/master/docs/documentation.md#decoratordecorator) say:
But then goes on to say:
And the following trivial example doesn't appear to change the signature at all?
What I want to do is create a decorator that will add a few optional keyword arguments to the decorated function. At first I thought I should be able to do something like:
But this returns a decorator factory (also useful, but not for me in this case).
Then, I thought I could do it with
decorate
, like this:But this doesn't work. The decorated function still only accepts the original keyword arguments.
I guess the two methods are functionally equivalent, but
decorator.decorate
allows to do something with the original function at the time the decorator is created (vs at the time runtime, withdecorator.decorator
.I also found #55 and #58 which seem to imply that signature-changing decorators are not supported at all and go against the entire philosophy of
decorator.py
.But this seems to be a direct contradiction of the quoted docs:
Can I use
decorator.py
to create signature-changing decorators, with new required or optional args or keyword args?The text was updated successfully, but these errors were encountered: