diff --git a/Lib/inspect.py b/Lib/inspect.py index aa951d83e24..4899cbf9f05 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -944,8 +944,14 @@ def getcallargs(func, *positional, **named): f_name, 'at most' if defaults else 'exactly', num_args, 'arguments' if num_args > 1 else 'argument', num_total)) elif num_args == 0 and num_total: - raise TypeError('%s() takes no arguments (%d given)' % - (f_name, num_total)) + if varkw or kwonlyargs: + if num_pos: + # XXX: We should use num_pos, but Python also uses num_total: + raise TypeError('%s() takes exactly 0 positional arguments ' + '(%d given)' % (f_name, num_total)) + else: + raise TypeError('%s() takes no arguments (%d given)' % + (f_name, num_total)) for arg in itertools.chain(args, kwonlyargs): if arg in named: diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index 331d2475001..7d7e16e0e15 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -632,6 +632,16 @@ class TestGetcallargsFunctions(unittest.TestCase): self.assertEqualCallArgs(f, '2, c=4, **collections.UserDict(b=3)') self.assertEqualCallArgs(f, 'b=2, **collections.UserDict(a=3, c=4)') + def test_varkw_only(self): + # issue11256: + f = self.makeCallable('**c') + self.assertEqualCallArgs(f, '') + self.assertEqualCallArgs(f, 'a=1') + self.assertEqualCallArgs(f, 'a=1, b=2') + self.assertEqualCallArgs(f, 'c=3, **{"a": 1, "b": 2}') + self.assertEqualCallArgs(f, '**collections.UserDict(a=1, b=2)') + self.assertEqualCallArgs(f, 'c=3, **collections.UserDict(a=1, b=2)') + def test_keyword_only(self): f = self.makeCallable('a=3, *, c, d=2') self.assertEqualCallArgs(f, 'c=3') @@ -643,6 +653,11 @@ class TestGetcallargsFunctions(unittest.TestCase): self.assertEqualException(f, 'a=3') self.assertEqualException(f, 'd=4') + f = self.makeCallable('*, c, d=2') + self.assertEqualCallArgs(f, 'c=3') + self.assertEqualCallArgs(f, 'c=3, d=4') + self.assertEqualCallArgs(f, 'd=4, c=3') + def test_multiple_features(self): f = self.makeCallable('a, b=2, *f, **g') self.assertEqualCallArgs(f, '2, 3, 7') @@ -656,6 +671,17 @@ class TestGetcallargsFunctions(unittest.TestCase): '(4,[5,6])]), **collections.UserDict(' 'y=9, z=10)') + f = self.makeCallable('a, b=2, *f, x, y=99, **g') + self.assertEqualCallArgs(f, '2, 3, x=8') + self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]') + self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9, z=10') + self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9, z=10') + self.assertEqualCallArgs(f, 'x=8, *collections.UserList(' + '[2, 3, (4,[5,6])]), q=0, **{"y":9, "z":10}') + self.assertEqualCallArgs(f, '2, x=8, *collections.UserList([3, ' + '(4,[5,6])]), q=0, **collections.UserDict(' + 'y=9, z=10)') + def test_errors(self): f0 = self.makeCallable('') f1 = self.makeCallable('a, b') @@ -692,6 +718,13 @@ class TestGetcallargsFunctions(unittest.TestCase): # - for functions and bound methods: unexpected keyword 'c' # - for unbound methods: multiple values for keyword 'a' #self.assertEqualException(f, '1, c=3, a=2') + # issue11256: + f3 = self.makeCallable('**c') + self.assertEqualException(f3, '1, 2') + self.assertEqualException(f3, '1, 2, a=1, b=2') + f4 = self.makeCallable('*, a, b=0') + self.assertEqualException(f3, '1, 2') + self.assertEqualException(f3, '1, 2, a=1, b=2') class TestGetcallargsMethods(TestGetcallargsFunctions): diff --git a/Misc/NEWS b/Misc/NEWS index 0341dd61305..23b5e6a481b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Core and Builtins Library ------- +- Issue #11256: Fix inspect.getcallargs on functions that take only keyword + arguments. + - Issue #11696: Fix ID generation in msilib. - itertools.accumulate now supports an optional *func* argument for