functions with kwargs
The signature binding fails if the function contains kwarg_sources.
Reproduce
from varname import nameof
def fn(var, **kwargs):
print(nameof(var, frame=2))
# ...
x = 5
fn(x) # OK
fn(x, y=6) # Error
Traceback
Traceback (most recent call last):
File "/home/hein_f0/dev/slki-code/.venv/lib/python3.11/site-packages/varname/core.py", line 469, in argname
argument_sources = get_argument_sources(
^^^^^^^^^^^^^^^^^^^^^
File "/home/hein_f0/dev/slki-code/.venv/lib/python3.11/site-packages/varname/utils.py", line 442, in get_argument_sources
bound_args = signature.bind_partial(*arg_sources, **kwarg_sources)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/inspect.py", line 3219, in bind_partial
return self._bind(args, kwargs, partial=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/inspect.py", line 3201, in _bind
raise TypeError(
TypeError: got an unexpected keyword argument 'y'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/hein_f0/dev/slki-code/test.py", line 11, in <module>
fn(x, y=6) # Error
^^^^^^^^^^
File "/home/hein_f0/dev/slki-code/test.py", line 5, in fn
print(nameof(var, frame=2))
^^^^^^^^^^^^^^^^^^^^
File "/home/hein_f0/dev/slki-code/.venv/lib/python3.11/site-packages/varname/core.py", line 333, in nameof
out = argname(
^^^^^^^^
File "/home/hein_f0/dev/slki-code/.venv/lib/python3.11/site-packages/varname/core.py", line 476, in argname
raise ImproperUseError(
varname.utils.ImproperUseError: Have you specified the right `frame` or `func`?
Problem
If I am not mistaken, the issue lies in line 442:
https://github.com/pwwang/python-varname/blob/1e07fcecef2d15c6802b76fe45bf9230a77d4832/varname/utils.py#L431-L442
The signature here is the nameof function: <Signature (var: Any, *more_vars: Any, frame: int = 1, vars_only: bool = True) -> Union[str, Tuple[str, ...]]> and therefore does not take any kwarg_sources from the source function fn.
Workaround
None, as far as I know.
Would you mind submitting a PR?
To be honest, I do not know how much the following fix would destroy, but a possible fix could be:
# <Signature (a, b, c, d=4)>
signature = inspect.signature(func, follow_wrapped=False)
# func(y, x, c=z)
# ['y', 'x'], {'c': 'z'}
arg_sources = [
argnode_source(source, argnode, vars_only) for argnode in node.args
]
kwarg_sources = {
argnode.arg: argnode_source(source, argnode.value, vars_only)
for argnode in node.keywords
if argnode.arg is not None
}
- bound_args = signature.bind_partial(*arg_sources, **kwarg_sources)
+ bound_args = signature.bind_partial(*arg_sources, *kwarg_sources.values())
argument_sources = bound_args.arguments
An alternative (quick and dirty) fix, which ignores all kwargs, would be to adjust the final signature of nameof (and others):
def nameof(
var: Any,
*more_vars: Any,
frame: int = 1,
vars_only: bool = True,
+ **kwargs,
) -> Union[str, Tuple[str, ...]]:
I could look further into it if issue #115 is solved.
Since nameof is already deprecated, I am closing this issue.