Commit 64c8f705 authored by Michael Seifert's avatar Michael Seifert Committed by Serhiy Storchaka

bpo-29951: Include function name for some error messages in `PyArg_ParseTuple*` (#916)

Also changed format specifier for function name from "%s" to "%.200s"
and exception messages should start with lowercase letter.
parent a2a9ddd9
...@@ -533,19 +533,19 @@ class SkipitemTest(unittest.TestCase): ...@@ -533,19 +533,19 @@ class SkipitemTest(unittest.TestCase):
parse((1, 2, 3), {}, b'OOO', ['', '', 'a']) parse((1, 2, 3), {}, b'OOO', ['', '', 'a'])
parse((1, 2), {'a': 3}, b'OOO', ['', '', 'a']) parse((1, 2), {'a': 3}, b'OOO', ['', '', 'a'])
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r'Function takes at least 2 positional arguments \(1 given\)'): r'function takes at least 2 positional arguments \(1 given\)'):
parse((1,), {'a': 3}, b'OOO', ['', '', 'a']) parse((1,), {'a': 3}, b'OOO', ['', '', 'a'])
parse((1,), {}, b'O|OO', ['', '', 'a']) parse((1,), {}, b'O|OO', ['', '', 'a'])
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r'Function takes at least 1 positional arguments \(0 given\)'): r'function takes at least 1 positional arguments \(0 given\)'):
parse((), {}, b'O|OO', ['', '', 'a']) parse((), {}, b'O|OO', ['', '', 'a'])
parse((1, 2), {'a': 3}, b'OO$O', ['', '', 'a']) parse((1, 2), {'a': 3}, b'OO$O', ['', '', 'a'])
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r'Function takes exactly 2 positional arguments \(1 given\)'): r'function takes exactly 2 positional arguments \(1 given\)'):
parse((1,), {'a': 3}, b'OO$O', ['', '', 'a']) parse((1,), {'a': 3}, b'OO$O', ['', '', 'a'])
parse((1,), {}, b'O|O$O', ['', '', 'a']) parse((1,), {}, b'O|O$O', ['', '', 'a'])
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r'Function takes at least 1 positional arguments \(0 given\)'): r'function takes at least 1 positional arguments \(0 given\)'):
parse((), {}, b'O|O$O', ['', '', 'a']) parse((), {}, b'O|O$O', ['', '', 'a'])
with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'): with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'):
parse((1,), {}, b'O|$OO', ['', '', 'a']) parse((1,), {}, b'O|$OO', ['', '', 'a'])
......
...@@ -1090,7 +1090,7 @@ class ImportErrorTests(unittest.TestCase): ...@@ -1090,7 +1090,7 @@ class ImportErrorTests(unittest.TestCase):
self.assertEqual(exc.name, 'somename') self.assertEqual(exc.name, 'somename')
self.assertEqual(exc.path, 'somepath') self.assertEqual(exc.path, 'somepath')
msg = "'invalid' is an invalid keyword argument for this function" msg = "'invalid' is an invalid keyword argument for ImportError"
with self.assertRaisesRegex(TypeError, msg): with self.assertRaisesRegex(TypeError, msg):
ImportError('test', invalid='keyword') ImportError('test', invalid='keyword')
......
...@@ -553,7 +553,8 @@ class Keywords_TestCase(unittest.TestCase): ...@@ -553,7 +553,8 @@ class Keywords_TestCase(unittest.TestCase):
try: try:
getargs_keywords(arg1=(1,2)) getargs_keywords(arg1=(1,2))
except TypeError as err: except TypeError as err:
self.assertEqual(str(err), "Required argument 'arg2' (pos 2) not found") self.assertEqual(
str(err), "function missing required argument 'arg2' (pos 2)")
else: else:
self.fail('TypeError should have been raised') self.fail('TypeError should have been raised')
...@@ -626,16 +627,16 @@ class KeywordOnly_TestCase(unittest.TestCase): ...@@ -626,16 +627,16 @@ class KeywordOnly_TestCase(unittest.TestCase):
) )
# required arg missing # required arg missing
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"Required argument 'required' \(pos 1\) not found"): r"function missing required argument 'required' \(pos 1\)"):
getargs_keyword_only(optional=2) getargs_keyword_only(optional=2)
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"Required argument 'required' \(pos 1\) not found"): r"function missing required argument 'required' \(pos 1\)"):
getargs_keyword_only(keyword_only=3) getargs_keyword_only(keyword_only=3)
def test_too_many_args(self): def test_too_many_args(self):
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"Function takes at most 2 positional arguments \(3 given\)"): r"function takes at most 2 positional arguments \(3 given\)"):
getargs_keyword_only(1, 2, 3) getargs_keyword_only(1, 2, 3)
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
...@@ -674,11 +675,11 @@ class PositionalOnlyAndKeywords_TestCase(unittest.TestCase): ...@@ -674,11 +675,11 @@ class PositionalOnlyAndKeywords_TestCase(unittest.TestCase):
self.assertEqual(self.getargs(1), (1, -1, -1)) self.assertEqual(self.getargs(1), (1, -1, -1))
# required positional arg missing # required positional arg missing
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"Function takes at least 1 positional arguments \(0 given\)"): r"function takes at least 1 positional arguments \(0 given\)"):
self.getargs() self.getargs()
with self.assertRaisesRegex(TypeError, with self.assertRaisesRegex(TypeError,
r"Function takes at least 1 positional arguments \(0 given\)"): r"function takes at least 1 positional arguments \(0 given\)"):
self.getargs(keyword=3) self.getargs(keyword=3)
def test_empty_keyword(self): def test_empty_keyword(self):
......
...@@ -1584,7 +1584,7 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs) ...@@ -1584,7 +1584,7 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs)
} }
if (!_PyDict_HasOnlyStringKeys(kwargs)) { if (!_PyDict_HasOnlyStringKeys(kwargs)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"keyword arguments must be strings"); "keywords must be strings");
return 0; return 0;
} }
return 1; return 1;
...@@ -1655,7 +1655,7 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, ...@@ -1655,7 +1655,7 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs); nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs);
if (nargs + nkwargs > len) { if (nargs + nkwargs > len) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%s%s takes at most %d argument%s (%zd given)", "%.200s%s takes at most %d argument%s (%zd given)",
(fname == NULL) ? "function" : fname, (fname == NULL) ? "function" : fname,
(fname == NULL) ? "" : "()", (fname == NULL) ? "" : "()",
len, len,
...@@ -1705,8 +1705,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, ...@@ -1705,8 +1705,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
} }
if (max < nargs) { if (max < nargs) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Function takes %s %d positional arguments" "%.200s%s takes %s %d positional arguments"
" (%d given)", " (%d given)",
(fname == NULL) ? "function" : fname,
(fname == NULL) ? "" : "()",
(min != INT_MAX) ? "at most" : "exactly", (min != INT_MAX) ? "at most" : "exactly",
max, nargs); max, nargs);
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
...@@ -1752,8 +1754,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, ...@@ -1752,8 +1754,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
* or the end of the format. */ * or the end of the format. */
} }
else { else {
PyErr_Format(PyExc_TypeError, "Required argument " PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
"'%s' (pos %d) not found", "argument '%s' (pos %d)",
(fname == NULL) ? "function" : fname,
(fname == NULL) ? "" : "()",
kwlist[i], i+1); kwlist[i], i+1);
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
...@@ -1779,8 +1783,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, ...@@ -1779,8 +1783,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
if (skip) { if (skip) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Function takes %s %d positional arguments" "%.200s%s takes %s %d positional arguments"
" (%d given)", " (%d given)",
(fname == NULL) ? "function" : fname,
(fname == NULL) ? "" : "()",
(Py_MIN(pos, min) < i) ? "at least" : "exactly", (Py_MIN(pos, min) < i) ? "at least" : "exactly",
Py_MIN(pos, min), nargs); Py_MIN(pos, min), nargs);
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
...@@ -1802,8 +1808,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, ...@@ -1802,8 +1808,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
if (current_arg) { if (current_arg) {
/* arg present in tuple and in dict */ /* arg present in tuple and in dict */
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Argument given by name ('%s') " "argument for %.200s%s given by name ('%s') "
"and position (%d)", "and position (%d)",
(fname == NULL) ? "function" : fname,
(fname == NULL) ? "" : "()",
kwlist[i], i+1); kwlist[i], i+1);
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
...@@ -1826,8 +1834,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, ...@@ -1826,8 +1834,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
if (!match) { if (!match) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"'%U' is an invalid keyword " "'%U' is an invalid keyword "
"argument for this function", "argument for %.200s%s",
key); key,
(fname == NULL) ? "this function" : fname,
(fname == NULL) ? "" : "()");
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
} }
...@@ -2060,7 +2070,7 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, ...@@ -2060,7 +2070,7 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
} }
if (nargs + nkwargs > len) { if (nargs + nkwargs > len) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%s%s takes at most %d argument%s (%zd given)", "%.200s%s takes at most %d argument%s (%zd given)",
(parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "function" : parser->fname,
(parser->fname == NULL) ? "" : "()", (parser->fname == NULL) ? "" : "()",
len, len,
...@@ -2070,7 +2080,9 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, ...@@ -2070,7 +2080,9 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
} }
if (parser->max < nargs) { if (parser->max < nargs) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Function takes %s %d positional arguments (%d given)", "%200s%s takes %s %d positional arguments (%d given)",
(parser->fname == NULL) ? "function" : parser->fname,
(parser->fname == NULL) ? "" : "()",
(parser->min != INT_MAX) ? "at most" : "exactly", (parser->min != INT_MAX) ? "at most" : "exactly",
parser->max, nargs); parser->max, nargs);
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
...@@ -2115,15 +2127,19 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, ...@@ -2115,15 +2127,19 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
if (i < pos) { if (i < pos) {
Py_ssize_t min = Py_MIN(pos, parser->min); Py_ssize_t min = Py_MIN(pos, parser->min);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Function takes %s %d positional arguments" "%.200s%s takes %s %d positional arguments"
" (%d given)", " (%d given)",
(parser->fname == NULL) ? "function" : parser->fname,
(parser->fname == NULL) ? "" : "()",
min < parser->max ? "at least" : "exactly", min < parser->max ? "at least" : "exactly",
min, nargs); min, nargs);
} }
else { else {
keyword = PyTuple_GET_ITEM(kwtuple, i - pos); keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
PyErr_Format(PyExc_TypeError, "Required argument " PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
"'%U' (pos %d) not found", "argument '%U' (pos %d)",
(parser->fname == NULL) ? "function" : parser->fname,
(parser->fname == NULL) ? "" : "()",
keyword, i+1); keyword, i+1);
} }
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
...@@ -2153,8 +2169,10 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, ...@@ -2153,8 +2169,10 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
if (current_arg) { if (current_arg) {
/* arg present in tuple and in dict */ /* arg present in tuple and in dict */
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Argument given by name ('%U') " "argument for %.200s%s given by name ('%U') "
"and position (%d)", "and position (%d)",
(parser->fname == NULL) ? "function" : parser->fname,
(parser->fname == NULL) ? "" : "()",
keyword, i+1); keyword, i+1);
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
...@@ -2184,8 +2202,10 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, ...@@ -2184,8 +2202,10 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
if (!match) { if (!match) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"'%U' is an invalid keyword " "'%U' is an invalid keyword "
"argument for this function", "argument for %.200s%s",
keyword); keyword,
(parser->fname == NULL) ? "this function" : parser->fname,
(parser->fname == NULL) ? "" : "()");
} }
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
...@@ -2365,7 +2385,7 @@ unpack_stack(PyObject **args, Py_ssize_t nargs, const char *name, ...@@ -2365,7 +2385,7 @@ unpack_stack(PyObject **args, Py_ssize_t nargs, const char *name,
if (name != NULL) if (name != NULL)
PyErr_Format( PyErr_Format(
PyExc_TypeError, PyExc_TypeError,
"%s expected %s%zd arguments, got %zd", "%.200s expected %s%zd arguments, got %zd",
name, (min == max ? "" : "at least "), min, nargs); name, (min == max ? "" : "at least "), min, nargs);
else else
PyErr_Format( PyErr_Format(
...@@ -2384,7 +2404,7 @@ unpack_stack(PyObject **args, Py_ssize_t nargs, const char *name, ...@@ -2384,7 +2404,7 @@ unpack_stack(PyObject **args, Py_ssize_t nargs, const char *name,
if (name != NULL) if (name != NULL)
PyErr_Format( PyErr_Format(
PyExc_TypeError, PyExc_TypeError,
"%s expected %s%zd arguments, got %zd", "%.200s expected %s%zd arguments, got %zd",
name, (min == max ? "" : "at most "), max, nargs); name, (min == max ? "" : "at most "), max, nargs);
else else
PyErr_Format( PyErr_Format(
...@@ -2469,7 +2489,7 @@ _PyArg_NoKeywords(const char *funcname, PyObject *kwargs) ...@@ -2469,7 +2489,7 @@ _PyArg_NoKeywords(const char *funcname, PyObject *kwargs)
return 1; return 1;
} }
PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments", PyErr_Format(PyExc_TypeError, "%.200s does not take keyword arguments",
funcname); funcname);
return 0; return 0;
} }
...@@ -2486,7 +2506,7 @@ _PyArg_NoStackKeywords(const char *funcname, PyObject *kwnames) ...@@ -2486,7 +2506,7 @@ _PyArg_NoStackKeywords(const char *funcname, PyObject *kwnames)
return 1; return 1;
} }
PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments", PyErr_Format(PyExc_TypeError, "%.200s does not take keyword arguments",
funcname); funcname);
return 0; return 0;
} }
...@@ -2504,7 +2524,7 @@ _PyArg_NoPositional(const char *funcname, PyObject *args) ...@@ -2504,7 +2524,7 @@ _PyArg_NoPositional(const char *funcname, PyObject *args)
if (PyTuple_GET_SIZE(args) == 0) if (PyTuple_GET_SIZE(args) == 0)
return 1; return 1;
PyErr_Format(PyExc_TypeError, "%s does not take positional arguments", PyErr_Format(PyExc_TypeError, "%.200s does not take positional arguments",
funcname); funcname);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment