From bf9075a0c55186d2f34df63e6c8512dd6414ff4b Mon Sep 17 00:00:00 2001 From: Oren Milman Date: Wed, 23 Aug 2017 21:16:48 +0300 Subject: bpo-31229: Fixed wrong error messages when too many keyword arguments are received. (#3180) --- Lib/test/test_call.py | 21 +++++++++++++++++++++ Python/getargs.c | 10 ++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index b004b58..3f9987c 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -7,6 +7,7 @@ except ImportError: _testcapi = None import struct import collections +import itertools # The test cases here cover several paths through the function calling # code. They depend on the METH_XXX flag that is used to define a C @@ -194,6 +195,26 @@ class CFunctionCallsErrorMessages(unittest.TestCase): msg = r"^classmethod\(\) takes no keyword arguments$" self.assertRaisesRegex(TypeError, msg, classmethod, func=id) + def test_varargs14_kw(self): + msg = r"^product\(\) takes at most 1 keyword argument \(2 given\)$" + self.assertRaisesRegex(TypeError, msg, + itertools.product, 0, repeat=1, foo=2) + + def test_varargs15_kw(self): + msg = r"^ImportError\(\) takes at most 2 keyword arguments \(3 given\)$" + self.assertRaisesRegex(TypeError, msg, + ImportError, 0, name=1, path=2, foo=3) + + def test_varargs16_kw(self): + msg = r"^min\(\) takes at most 2 keyword arguments \(3 given\)$" + self.assertRaisesRegex(TypeError, msg, + min, 0, default=1, key=2, foo=3) + + def test_varargs17_kw(self): + msg = r"^print\(\) takes at most 4 keyword arguments \(5 given\)$" + self.assertRaisesRegex(TypeError, msg, + print, 0, sep=1, end=2, file=3, flush=4, foo=5) + def test_oldargs0_1(self): msg = r"keys\(\) takes no arguments \(1 given\)" self.assertRaisesRegex(TypeError, msg, {}.keys, 0) diff --git a/Python/getargs.c b/Python/getargs.c index 4645b0f..4b969d9 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1654,11 +1654,14 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, nargs = PyTuple_GET_SIZE(args); nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs); if (nargs + nkwargs > len) { + /* Adding "keyword" (when nargs == 0) prevents producing wrong error + messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, - "%.200s%s takes at most %d argument%s (%zd given)", + "%.200s%s takes at most %d %sargument%s (%zd given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", len, + (nargs == 0) ? "keyword " : "", (len == 1) ? "" : "s", nargs + nkwargs); return cleanreturn(0, &freelist); @@ -2077,11 +2080,14 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, nkwargs = 0; } if (nargs + nkwargs > len) { + /* Adding "keyword" (when nargs == 0) prevents producing wrong error + messages in some special cases (see bpo-31229). */ PyErr_Format(PyExc_TypeError, - "%.200s%s takes at most %d argument%s (%zd given)", + "%.200s%s takes at most %d %sargument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", len, + (nargs == 0) ? "keyword " : "", (len == 1) ? "" : "s", nargs + nkwargs); return cleanreturn(0, &freelist); -- cgit v0.12