boltons
boltons copied to clipboard
Python `funcutils.wraps` breaks when keyword only arguments involved
Code worth 1000 words:
>>> from boltons.funcutils import wraps
>>>
>>> def g(a: float, b=10):
... return a * b
>>>
>>> def f(a: int, *, b=1):
... return a * b
>>>
>>> # all is well here...
>>> assert f(3) == 3
>>> assert g(3) == 30
>>> assert wraps(f)(g)(3) == 3 # yay, g got the f default (not so with functools.wraps!)
>>>
>>> # but this doesn't work
>>> wraps(g)(f)(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<boltons.funcutils.FunctionBuilder-1>", line 2, in g
TypeError: f() takes 1 positional argument but 2 were given
Ah, I was confused when this bug came in, bc I've got scars from maintaining this area and dealing with the expansion of function signature semantics in python 3
You'll notice that when kw-only args are involved the first time (wraps(f)(g)
) it works fine. The other way around, however, wraps(g)(f)
fails, because by the very nature of funcutils.wraps
, you're trying to give f
the same signature as g
. And f
's signature is not like g
's. g
supports positional b
and f()
does not.
If you want to make a wrapper which converts a keyword-only argument to one that can be positional or keyword only, that'll require a different approach for now.
A potential fix would be to pass all function arguments as keywords. But doubt that's the right direction, because, while I have yet to add positional argument only support, that'll definitely throw a wrench into things.