[issue23764] functools.wraps should be able to change function argspec as well
productivememberofsociety666
report at bugs.python.org
Thu Mar 26 00:50:07 CET 2015
productivememberofsociety666 added the comment:
You're probably right and it's next to impossible to implement what I want in a clean manner. I'll get back to that at the end, but first for completeness's sake two examples to illustrate what this issue is even about.
````
import functools
def wrapper(func):
@functools.wraps(func)
def new_func(*args, **kwargs):
pass
return new_func
def to_be_wrapped(a):
pass
wrapped = wrapper(to_be_wrapped)
wrapped(1) # Ok
wrapped(1, 2, 3) # Also ok, but shouldn't be! Should raise TypeError
````
The second call to wrapped() should fail because it's supposed to be a wrapper around to_be_wrapped(), which only takes 1 argument. But it succeeds because functools.wraps only changes "superficial" function attributes such as its signature or docstring. This creates a mismatch between expected and actual behaviour of wrapped().
Contrast this with how it works when using the decorator package I mentioned:
````
import decorator
def to_be_wrapped(x):
print("f(x) called")
pass
def _wrapper(func, *args, **kwargs):
# Put actual functionality of your decorator here
pass
def wrapper(func):
return decorator.decorator(_wrapper, func)
wrapped = wrapper(to_be_wrapped)
wrapped(1) # Ok, because to_be_wrapped takes exactly 1 argument
wrapped(1, 2, 3) # raises TypeError for too many arguments, as it should
````
Like I said, the details of how it is used are different from those of functools.wraps. But the important thing is that, at the end, wrapped()'s argspec matches that of to_be_wrapped() and an appropriate error is raised by the second call.
Note that this does NOT work via propagation from a call to to_be_wrapped() or anything of the sort, as can be verified by the lack of output to stdout.
Now, the only problem is: I had a look at how this is achieved in the decorator package's source code and if I understand it correctly, they are doing some nasty nasty things with exec() to create a function with an argspec of their choosing at runtime. If this is in fact the only way to do it, I agree that it has no place in the standard library and should only be available via 3rd party libraries. Sorry for wasting your time then.
----------
_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue23764>
_______________________________________
More information about the Python-bugs-list
mailing list