diff options
author | Yury Selivanov <yselivanov@sprymix.com> | 2015-05-16 17:45:09 (GMT) |
---|---|---|
committer | Yury Selivanov <yselivanov@sprymix.com> | 2015-05-16 17:45:09 (GMT) |
commit | b907a513c8285410d93adc2895508985838fe1a7 (patch) | |
tree | 80450ad00573547efc68174d32388ce1b140bbfc | |
parent | 1392f71c3927c9d81969200f5dfff9fb832cde0b (diff) | |
download | cpython-b907a513c8285410d93adc2895508985838fe1a7.zip cpython-b907a513c8285410d93adc2895508985838fe1a7.tar.gz cpython-b907a513c8285410d93adc2895508985838fe1a7.tar.bz2 |
Issue 24190: Add inspect.BoundArguments.apply_defaults() method.
-rw-r--r-- | Doc/library/inspect.rst | 41 | ||||
-rw-r--r-- | Doc/whatsnew/3.5.rst | 3 | ||||
-rw-r--r-- | Lib/inspect.py | 30 | ||||
-rw-r--r-- | Lib/test/test_inspect.py | 35 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
5 files changed, 91 insertions, 21 deletions
diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 444d2be..3ee177d 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -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:: diff --git a/Doc/whatsnew/3.5.rst b/Doc/whatsnew/3.5.rst index 7c845cd..92e1142 100644 --- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -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`.) diff --git a/Lib/inspect.py b/Lib/inspect.py index 9389f3b..8d2920a 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -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 diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index bed3bad..e712efb 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -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): @@ -131,6 +131,9 @@ Library - Issue 22547: Implement informative __repr__ for inspect.BoundArguments. Contributed by Yury Selivanov. +- Issue 24190: Implement inspect.BoundArgument.apply_defaults() method. + Contributed by Yury Selivanov. + Tests ----- |