Issue 24190: Add inspect.BoundArguments.apply_defaults() method.
This commit is contained in:
parent
1392f71c39
commit
b907a513c8
|
@ -667,27 +667,8 @@ function.
|
|||
|
||||
Arguments for which :meth:`Signature.bind` or
|
||||
:meth:`Signature.bind_partial` relied on a default value are skipped.
|
||||
However, if needed, it is easy to include them.
|
||||
|
||||
::
|
||||
|
||||
>>> def foo(a, b=10):
|
||||
... pass
|
||||
|
||||
>>> sig = signature(foo)
|
||||
>>> ba = sig.bind(5)
|
||||
|
||||
>>> ba.args, ba.kwargs
|
||||
((5,), {})
|
||||
|
||||
>>> 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
|
||||
|
||||
>>> ba.args, ba.kwargs
|
||||
((5, 10), {})
|
||||
|
||||
However, if needed, use :meth:`BoundArguments.apply_defaults` to add
|
||||
them.
|
||||
|
||||
.. attribute:: BoundArguments.args
|
||||
|
||||
|
@ -703,6 +684,24 @@ function.
|
|||
|
||||
A reference to the parent :class:`Signature` object.
|
||||
|
||||
.. method:: BoundArguments.apply_defaults()
|
||||
|
||||
Set default values for missing arguments.
|
||||
|
||||
For variable-positional arguments (``*args``) the default is an
|
||||
empty tuple.
|
||||
|
||||
For variable-keyword arguments (``**kwargs``) the default is an
|
||||
empty dict.
|
||||
|
||||
::
|
||||
|
||||
>>> def foo(a, b='ham', *args): pass
|
||||
>>> ba = inspect.signature(foo).bind('spam')
|
||||
>>> ba.apply_defaults()
|
||||
>>> ba.arguments
|
||||
OrderedDict([('a', 'spam'), ('b', 'ham'), ('args', ())])
|
||||
|
||||
The :attr:`args` and :attr:`kwargs` properties can be used to invoke
|
||||
functions::
|
||||
|
||||
|
|
|
@ -400,6 +400,9 @@ inspect
|
|||
picklable and hashable. (Contributed by Yury Selivanov in :issue:`20726`
|
||||
and :issue:`20334`.)
|
||||
|
||||
* New method :meth:`inspect.BoundArguments.apply_defaults`. (Contributed
|
||||
by Yury Selivanov in :issue:`24190`.)
|
||||
|
||||
* New class method :meth:`inspect.Signature.from_callable`, which makes
|
||||
subclassing of :class:`~inspect.Signature` easier. (Contributed
|
||||
by Yury Selivanov and Eric Snow in :issue:`17373`.)
|
||||
|
|
|
@ -2443,6 +2443,36 @@ class BoundArguments:
|
|||
|
||||
return kwargs
|
||||
|
||||
def apply_defaults(self):
|
||||
"""Set default values for missing arguments.
|
||||
|
||||
For variable-positional arguments (*args) the default is an
|
||||
empty tuple.
|
||||
|
||||
For variable-keyword arguments (**kwargs) the default is an
|
||||
empty dict.
|
||||
"""
|
||||
arguments = self.arguments
|
||||
if not arguments:
|
||||
return
|
||||
new_arguments = []
|
||||
for name, param in self._signature.parameters.items():
|
||||
try:
|
||||
new_arguments.append((name, arguments[name]))
|
||||
except KeyError:
|
||||
if param.default is not _empty:
|
||||
val = param.default
|
||||
elif param.kind is _VAR_POSITIONAL:
|
||||
val = ()
|
||||
elif param.kind is _VAR_KEYWORD:
|
||||
val = {}
|
||||
else:
|
||||
# This BoundArguments was likely produced by
|
||||
# Signature.bind_partial().
|
||||
continue
|
||||
new_arguments.append((name, val))
|
||||
self.arguments = OrderedDict(new_arguments)
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self is other or
|
||||
(issubclass(other.__class__, BoundArguments) and
|
||||
|
|
|
@ -3153,6 +3153,41 @@ class TestBoundArguments(unittest.TestCase):
|
|||
ba = sig.bind(20, 30, z={})
|
||||
self.assertRegex(repr(ba), r'<BoundArguments \(a=20,.*\}\}\)>')
|
||||
|
||||
def test_signature_bound_arguments_apply_defaults(self):
|
||||
def foo(a, b=1, *args, c:1={}, **kw): pass
|
||||
sig = inspect.signature(foo)
|
||||
|
||||
ba = sig.bind(20)
|
||||
ba.apply_defaults()
|
||||
self.assertEqual(
|
||||
list(ba.arguments.items()),
|
||||
[('a', 20), ('b', 1), ('args', ()), ('c', {}), ('kw', {})])
|
||||
|
||||
# Make sure that we preserve the order:
|
||||
# i.e. 'c' should be *before* 'kw'.
|
||||
ba = sig.bind(10, 20, 30, d=1)
|
||||
ba.apply_defaults()
|
||||
self.assertEqual(
|
||||
list(ba.arguments.items()),
|
||||
[('a', 10), ('b', 20), ('args', (30,)), ('c', {}), ('kw', {'d':1})])
|
||||
|
||||
# Make sure that BoundArguments produced by bind_partial()
|
||||
# are supported.
|
||||
def foo(a, b): pass
|
||||
sig = inspect.signature(foo)
|
||||
ba = sig.bind_partial(20)
|
||||
ba.apply_defaults()
|
||||
self.assertEqual(
|
||||
list(ba.arguments.items()),
|
||||
[('a', 20)])
|
||||
|
||||
# Test no args
|
||||
def foo(): pass
|
||||
sig = inspect.signature(foo)
|
||||
ba = sig.bind()
|
||||
ba.apply_defaults()
|
||||
self.assertEqual(list(ba.arguments.items()), [])
|
||||
|
||||
|
||||
class TestSignaturePrivateHelpers(unittest.TestCase):
|
||||
def test_signature_get_bound_param(self):
|
||||
|
|
Loading…
Reference in New Issue