msg232150 - (view) |
Author: Walter Dörwald (doerwalter) *  |
Date: 2014-12-04 20:14 |
inspect.Signature.bind() doesn't add values for parameters that are unspecified but have a default value. The documentation at https://docs.python.org/3/library/inspect.html#inspect.BoundArguments.arguments includes an example how to add default values, but that example doesn't work for the * and ** parameters. This patch adds a new method Signature.bind_with_defaults() that works like Signature.bind(), but includes parameters with a default value (and can handle values for the * and ** parameters). |
|
|
msg232151 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2014-12-04 20:20 |
Can you give an example of what you say doesn't work? IIRC the reason this method isn't part of the API is because normally it isn't needed (the defaults are filled in when you do the actual call). What is your use case for needing the defaults to be pre-bound? |
|
|
msg232152 - (view) |
Author: Walter Dörwald (doerwalter) *  |
Date: 2014-12-04 20:43 |
The following doesn't work:: import inspect def foo(*args, **kwargs): return (args, kwargs) # Code from https://docs.python.org/3/library/inspect.html#inspect.BoundArguments.arguments to fill in the defaults sig = inspect.signature(foo) ba = sig.bind() for param in sig.parameters.values(): if param.name not in ba.arguments: ba.arguments[param.name] = param.default print(foo(*ba.args, **ba.kwargs)) instead it gives the following traceback:: Traceback (most recent call last): File "sig_test.py", line 16, in print(foo(*ba.args, **ba.kwargs)) File "/Users/walter/.local/lib/python3.4/inspect.py", line 2246, in args args.extend(arg) TypeError: 'type' object is not iterable In my use case there isn't a call to a function implemented in Python. Instead I'm implementing a templating languages that supports defining a signature for a template. Calling the template binds the arguments and inside the template the variables simply are a dictionary. I.e. define the template like this: t = Template("", signature="a, b=23") Then you can call it like this: t(17) and inside the template the variables will be {"a": 17, "b": 23}. The signature argument in the Template constructor will be parsed into an inspect.Signature object and I'd like to use Signature.bind() to get the final variables dictionary. |
|
|
msg232153 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2014-12-04 21:28 |
This is indeed a bit tricky. Your use case is pretty specialized (it doesn't involve any actual python functions), so I don't think by itself it argues for the inclusion of a _with_defaults method. The example fill-in in the docs fails because args and kwargs don't check for _empty as a possible value for the VAR_POSITIONAL (resp VAR_KEYWORD). So I think either we add that check to args and kwargs, or we add a _with_defaults method because filling in the defaults would no longer be a simple loop (and thus easy to get wrong). Let's see what Yury thinks. |
|
|
msg232154 - (view) |
Author: Yury Selivanov (yselivanov) *  |
Date: 2014-12-04 22:05 |
I think we should just fix the documentation, and update the code in example with a proper check: for param in sig.parameters.values(): if (param.name not in ba.arguments and param.default is not param.empty): ba.arguments[param.name] = param.default I'm -1 on adding '_with_defaults' method, because usually you don't need this (at least in my experience). |
|
|
msg232175 - (view) |
Author: Roundup Robot (python-dev)  |
Date: 2014-12-05 03:49 |
New changeset 71c38c233e5c by Yury Selivanov in branch '3.4': docs.inspect: Fix BoundArguments example. Issue #22998. https://hg.python.org/cpython/rev/71c38c233e5c New changeset 697adefaba6b by Yury Selivanov in branch 'default': docs.inspect: Fix BoundArguments example. Issue #22998. https://hg.python.org/cpython/rev/697adefaba6b |
|
|
msg232227 - (view) |
Author: Terry J. Reedy (terry.reedy) *  |
Date: 2014-12-05 23:57 |
Should this be closed now? |
|
|
msg232228 - (view) |
Author: Yury Selivanov (yselivanov) *  |
Date: 2014-12-06 00:05 |
> Should this be closed now? Yes, let's close it. David and Walter, you're welcome to re-open the issue if you want to discuss it in more detail. |
|
|
msg232234 - (view) |
Author: R. David Murray (r.david.murray) *  |
Date: 2014-12-06 01:32 |
I'm good with your solution, but I'm going to adjust the resolution by changing the component :) |
|
|
msg232375 - (view) |
Author: Walter Dörwald (doerwalter) *  |
Date: 2014-12-09 13:33 |
The updated code in the documentation still doesn't set the * and ** parameters. I would have preferred the following code: for param in sig.parameters.values(): if param.name not in ba.arguments: if param.kind is inspect.Parameter.VAR_POSITIONAL: default = () elif param.kind is inspect.Parameter.VAR_KEYWORD: default = {} else: default = param.default ba.arguments[param.name] = default |
|
|