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:
parent
8757ead38e
commit
38b0d5a778
@ -2258,6 +2258,8 @@ class Signature:
|
|||||||
parameters_ex = (param,)
|
parameters_ex = (param,)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
# No default, not VAR_KEYWORD, not VAR_POSITIONAL,
|
||||||
|
# not in `kwargs`
|
||||||
if partial:
|
if partial:
|
||||||
parameters_ex = (param,)
|
parameters_ex = (param,)
|
||||||
break
|
break
|
||||||
@ -2296,19 +2298,17 @@ class Signature:
|
|||||||
# keyword arguments
|
# keyword arguments
|
||||||
kwargs_param = None
|
kwargs_param = None
|
||||||
for param in itertools.chain(parameters_ex, parameters):
|
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:
|
if param.kind == _VAR_KEYWORD:
|
||||||
# Memorize that we have a '**kwargs'-like parameter
|
# Memorize that we have a '**kwargs'-like parameter
|
||||||
kwargs_param = param
|
kwargs_param = param
|
||||||
continue
|
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
|
param_name = param.name
|
||||||
try:
|
try:
|
||||||
arg_val = kwargs.pop(param_name)
|
arg_val = kwargs.pop(param_name)
|
||||||
|
@ -2516,6 +2516,15 @@ class TestSignatureBind(unittest.TestCase):
|
|||||||
self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6),
|
self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6),
|
||||||
(1, 2, 4, 5, 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"):
|
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
|
||||||
self.call(test, 1, 2, c_po=4)
|
self.call(test, 1, 2, c_po=4)
|
||||||
|
|
||||||
@ -2532,6 +2541,22 @@ class TestSignatureBind(unittest.TestCase):
|
|||||||
ba = sig.bind(1, self=2, b=3)
|
ba = sig.bind(1, self=2, b=3)
|
||||||
self.assertEqual(ba.args, (1, 2, 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):
|
class TestBoundArguments(unittest.TestCase):
|
||||||
def test_signature_bound_arguments_unhashable(self):
|
def test_signature_bound_arguments_unhashable(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user