diff options
-rw-r--r-- | Lib/inspect.py | 16 | ||||
-rw-r--r-- | Lib/test/test_inspect.py | 25 |
2 files changed, 33 insertions, 8 deletions
diff --git a/Lib/inspect.py b/Lib/inspect.py index 0e41626..c3fecb8 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -2258,6 +2258,8 @@ class Signature: parameters_ex = (param,) break else: + # No default, not VAR_KEYWORD, not VAR_POSITIONAL, + # not in `kwargs` if partial: parameters_ex = (param,) break @@ -2296,19 +2298,17 @@ class Signature: # keyword arguments kwargs_param = None for param in itertools.chain(parameters_ex, parameters): - if param.kind == _POSITIONAL_ONLY: - # This should never happen in case of a properly built - # Signature object (but let's have this check here - # to ensure correct behaviour just in case) - raise TypeError('{arg!r} parameter is positional only, ' - 'but was passed as a keyword'. \ - format(arg=param.name)) - if param.kind == _VAR_KEYWORD: # Memorize that we have a '**kwargs'-like parameter kwargs_param = param continue + if param.kind == _VAR_POSITIONAL: + # Named arguments don't refer to '*args'-like parameters. + # We only arrive here if the positional arguments ended + # before reaching the last parameter before *args. + continue + param_name = param.name try: arg_val = kwargs.pop(param_name) diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 1d251b9..1325c7a 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -2516,6 +2516,15 @@ class TestSignatureBind(unittest.TestCase): self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6), (1, 2, 4, 5, 6, {})) + self.assertEqual(self.call(test, 1, 2), + (1, 2, 3, 42, 50, {})) + + self.assertEqual(self.call(test, 1, 2, foo=4, bar=5), + (1, 2, 3, 4, 5, {})) + + with self.assertRaisesRegex(TypeError, "but was passed as a keyword"): + self.call(test, 1, 2, foo=4, bar=5, c_po=10) + with self.assertRaisesRegex(TypeError, "parameter is positional only"): self.call(test, 1, 2, c_po=4) @@ -2532,6 +2541,22 @@ class TestSignatureBind(unittest.TestCase): ba = sig.bind(1, self=2, b=3) self.assertEqual(ba.args, (1, 2, 3)) + def test_signature_bind_vararg_name(self): + def test(a, *args): + return a, args + sig = inspect.signature(test) + + with self.assertRaisesRegex(TypeError, "too many keyword arguments"): + sig.bind(a=0, args=1) + + def test(*args, **kwargs): + return args, kwargs + self.assertEqual(self.call(test, args=1), ((), {'args': 1})) + + sig = inspect.signature(test) + ba = sig.bind(args=1) + self.assertEqual(ba.arguments, {'kwargs': {'args': 1}}) + class TestBoundArguments(unittest.TestCase): def test_signature_bound_arguments_unhashable(self): |