diff --git a/Lib/test/test_call.py b/Lib/test/test_call.py index 45b34e46a5a..75a4a9ff812 100644 --- a/Lib/test/test_call.py +++ b/Lib/test/test_call.py @@ -160,19 +160,22 @@ class CFunctionCallsErrorMessages(unittest.TestCase): msg = r"^from_bytes\(\) takes at most 2 positional arguments \(3 given\)" self.assertRaisesRegex(TypeError, msg, int.from_bytes, b'a', 'little', False) - def test_varargs4(self): + def test_varargs1min(self): msg = r"get expected at least 1 argument, got 0" self.assertRaisesRegex(TypeError, msg, {}.get) - def test_varargs5(self): + msg = r"expected 1 argument, got 0" + self.assertRaisesRegex(TypeError, msg, {}.__delattr__) + + def test_varargs2min(self): msg = r"getattr expected at least 2 arguments, got 0" self.assertRaisesRegex(TypeError, msg, getattr) - def test_varargs6(self): + def test_varargs1max(self): msg = r"input expected at most 1 argument, got 2" self.assertRaisesRegex(TypeError, msg, input, 1, 2) - def test_varargs7(self): + def test_varargs2max(self): msg = r"get expected at most 2 arguments, got 3" self.assertRaisesRegex(TypeError, msg, {}.get, 1, 2, 3) diff --git a/Lib/test/test_getargs2.py b/Lib/test/test_getargs2.py index 44a01a48105..d9bcb1d75bd 100644 --- a/Lib/test/test_getargs2.py +++ b/Lib/test/test_getargs2.py @@ -682,11 +682,11 @@ class PositionalOnlyAndKeywords_TestCase(unittest.TestCase): self.assertEqual(self.getargs(1), (1, -1, -1)) # required positional arg missing with self.assertRaisesRegex(TypeError, - r"function takes at least 1 positional arguments \(0 given\)"): + r"function takes at least 1 positional argument \(0 given\)"): self.getargs() with self.assertRaisesRegex(TypeError, - r"function takes at least 1 positional arguments \(0 given\)"): + r"function takes at least 1 positional argument \(0 given\)"): self.getargs(keyword=3) def test_empty_keyword(self): @@ -1112,7 +1112,7 @@ class ParseTupleAndKeywords_Test(unittest.TestCase): parse((1,), {'a': 3}, 'OOO', ['', '', 'a']) parse((1,), {}, 'O|OO', ['', '', 'a']) with self.assertRaisesRegex(TypeError, - r'function takes at least 1 positional arguments \(0 given\)'): + r'function takes at least 1 positional argument \(0 given\)'): parse((), {}, 'O|OO', ['', '', 'a']) parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a']) with self.assertRaisesRegex(TypeError, @@ -1120,7 +1120,7 @@ class ParseTupleAndKeywords_Test(unittest.TestCase): parse((1,), {'a': 3}, 'OO$O', ['', '', 'a']) parse((1,), {}, 'O|O$O', ['', '', 'a']) with self.assertRaisesRegex(TypeError, - r'function takes at least 1 positional arguments \(0 given\)'): + r'function takes at least 1 positional argument \(0 given\)'): parse((), {}, 'O|O$O', ['', '', 'a']) with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'): parse((1,), {}, 'O|$OO', ['', '', 'a']) diff --git a/Misc/NEWS.d/next/C API/2018-07-24-11-57-35.bpo-34193.M6ch1Q.rst b/Misc/NEWS.d/next/C API/2018-07-24-11-57-35.bpo-34193.M6ch1Q.rst new file mode 100644 index 00000000000..da2a6116d44 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2018-07-24-11-57-35.bpo-34193.M6ch1Q.rst @@ -0,0 +1,2 @@ +Fix pluralization in TypeError messages in getargs.c and typeobject.c: +'1 argument' instead of '1 arguments' and '1 element' instead of '1 elements'. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d1f1e8cd24b..ace45ba5794 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5434,7 +5434,7 @@ check_num_args(PyObject *ob, int n) return 1; PyErr_Format( PyExc_TypeError, - "expected %d arguments, got %zd", n, PyTuple_GET_SIZE(ob)); + "expected %d argument%s, got %zd", n, n == 1 ? "" : "s", PyTuple_GET_SIZE(ob)); return 0; } diff --git a/Python/getargs.c b/Python/getargs.c index ac8bac3bf50..00e330dc5d3 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -540,8 +540,10 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, levels[0] = 0; if (toplevel) { PyOS_snprintf(msgbuf, bufsize, - "expected %d arguments, not %" PY_FORMAT_SIZE_T "d", - n, len); + "expected %d argument%s, not %" PY_FORMAT_SIZE_T "d", + n, + n == 1 ? "" : "s", + len); } else { PyOS_snprintf(msgbuf, bufsize, @@ -1718,12 +1720,14 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, } else { PyErr_Format(PyExc_TypeError, - "%.200s%s takes %s %d positional arguments" + "%.200s%s takes %s %d positional argument%s" " (%d given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", (min != INT_MAX) ? "at most" : "exactly", - max, nargs); + max, + max == 1 ? "" : "s", + nargs); } return cleanreturn(0, &freelist); } @@ -1797,12 +1801,14 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, if (skip) { PyErr_Format(PyExc_TypeError, - "%.200s%s takes %s %d positional arguments" + "%.200s%s takes %s %d positional argument%s" " (%d given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", (Py_MIN(pos, min) < i) ? "at least" : "exactly", - Py_MIN(pos, min), nargs); + Py_MIN(pos, min), + Py_MIN(pos, min) == 1 ? "" : "s", + nargs); return cleanreturn(0, &freelist); } @@ -2104,11 +2110,13 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, } else { PyErr_Format(PyExc_TypeError, - "%.200s%s takes %s %d positional arguments (%d given)", + "%.200s%s takes %s %d positional argument%s (%d given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", (parser->min != INT_MAX) ? "at most" : "exactly", - parser->max, nargs); + parser->max, + parser->max == 1 ? "" : "s", + nargs); } return cleanreturn(0, &freelist); } @@ -2152,12 +2160,14 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, if (i < pos) { Py_ssize_t min = Py_MIN(pos, parser->min); PyErr_Format(PyExc_TypeError, - "%.200s%s takes %s %d positional arguments" + "%.200s%s takes %s %d positional argument%s" " (%d given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", min < parser->max ? "at least" : "exactly", - min, nargs); + min, + min == 1 ? "" : "s", + nargs); } else { keyword = PyTuple_GET_ITEM(kwtuple, i - pos); @@ -2417,9 +2427,9 @@ unpack_stack(PyObject *const *args, Py_ssize_t nargs, const char *name, else PyErr_Format( PyExc_TypeError, - "unpacked tuple should have %s%zd elements," + "unpacked tuple should have %s%zd element%s," " but has %zd", - (min == max ? "" : "at least "), min, nargs); + (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs); return 0; } @@ -2436,9 +2446,9 @@ unpack_stack(PyObject *const *args, Py_ssize_t nargs, const char *name, else PyErr_Format( PyExc_TypeError, - "unpacked tuple should have %s%zd elements," + "unpacked tuple should have %s%zd element%s," " but has %zd", - (min == max ? "" : "at most "), max, nargs); + (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs); return 0; }