inspect.Signature.bind: Fix pos-only params with defaults; fix *args in named args #19140

Initial patch by Yann Kaiser (epsy).
This commit is contained in:
Yury Selivanov 2014-01-28 17:27:39 -05:00
parent 8757ead38e
commit 38b0d5a778
2 changed files with 33 additions and 8 deletions

View File

@ -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)

View File

@ -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):