Skip to content

Commit 64c8f70

Browse files
MSeifert04serhiy-storchaka
authored andcommitted
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.
1 parent a2a9ddd commit 64c8f70

File tree

4 files changed

+54
-33
lines changed

4 files changed

+54
-33
lines changed

Lib/test/test_capi.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,19 +533,19 @@ def test_positional_only(self):
533533
parse((1, 2, 3), {}, b'OOO', ['', '', 'a'])
534534
parse((1, 2), {'a': 3}, b'OOO', ['', '', 'a'])
535535
with self.assertRaisesRegex(TypeError,
536-
r'Function takes at least 2 positional arguments \(1 given\)'):
536+
r'function takes at least 2 positional arguments \(1 given\)'):
537537
parse((1,), {'a': 3}, b'OOO', ['', '', 'a'])
538538
parse((1,), {}, b'O|OO', ['', '', 'a'])
539539
with self.assertRaisesRegex(TypeError,
540-
r'Function takes at least 1 positional arguments \(0 given\)'):
540+
r'function takes at least 1 positional arguments \(0 given\)'):
541541
parse((), {}, b'O|OO', ['', '', 'a'])
542542
parse((1, 2), {'a': 3}, b'OO$O', ['', '', 'a'])
543543
with self.assertRaisesRegex(TypeError,
544-
r'Function takes exactly 2 positional arguments \(1 given\)'):
544+
r'function takes exactly 2 positional arguments \(1 given\)'):
545545
parse((1,), {'a': 3}, b'OO$O', ['', '', 'a'])
546546
parse((1,), {}, b'O|O$O', ['', '', 'a'])
547547
with self.assertRaisesRegex(TypeError,
548-
r'Function takes at least 1 positional arguments \(0 given\)'):
548+
r'function takes at least 1 positional arguments \(0 given\)'):
549549
parse((), {}, b'O|O$O', ['', '', 'a'])
550550
with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'):
551551
parse((1,), {}, b'O|$OO', ['', '', 'a'])

Lib/test/test_exceptions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ def test_attributes(self):
10901090
self.assertEqual(exc.name, 'somename')
10911091
self.assertEqual(exc.path, 'somepath')
10921092

1093-
msg = "'invalid' is an invalid keyword argument for this function"
1093+
msg = "'invalid' is an invalid keyword argument for ImportError"
10941094
with self.assertRaisesRegex(TypeError, msg):
10951095
ImportError('test', invalid='keyword')
10961096

Lib/test/test_getargs2.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,8 @@ def test_required_args(self):
553553
try:
554554
getargs_keywords(arg1=(1,2))
555555
except TypeError as err:
556-
self.assertEqual(str(err), "Required argument 'arg2' (pos 2) not found")
556+
self.assertEqual(
557+
str(err), "function missing required argument 'arg2' (pos 2)")
557558
else:
558559
self.fail('TypeError should have been raised')
559560

@@ -626,16 +627,16 @@ def test_required_args(self):
626627
)
627628
# required arg missing
628629
with self.assertRaisesRegex(TypeError,
629-
r"Required argument 'required' \(pos 1\) not found"):
630+
r"function missing required argument 'required' \(pos 1\)"):
630631
getargs_keyword_only(optional=2)
631632

632633
with self.assertRaisesRegex(TypeError,
633-
r"Required argument 'required' \(pos 1\) not found"):
634+
r"function missing required argument 'required' \(pos 1\)"):
634635
getargs_keyword_only(keyword_only=3)
635636

636637
def test_too_many_args(self):
637638
with self.assertRaisesRegex(TypeError,
638-
r"Function takes at most 2 positional arguments \(3 given\)"):
639+
r"function takes at most 2 positional arguments \(3 given\)"):
639640
getargs_keyword_only(1, 2, 3)
640641

641642
with self.assertRaisesRegex(TypeError,
@@ -674,11 +675,11 @@ def test_required_args(self):
674675
self.assertEqual(self.getargs(1), (1, -1, -1))
675676
# required positional arg missing
676677
with self.assertRaisesRegex(TypeError,
677-
r"Function takes at least 1 positional arguments \(0 given\)"):
678+
r"function takes at least 1 positional arguments \(0 given\)"):
678679
self.getargs()
679680

680681
with self.assertRaisesRegex(TypeError,
681-
r"Function takes at least 1 positional arguments \(0 given\)"):
682+
r"function takes at least 1 positional arguments \(0 given\)"):
682683
self.getargs(keyword=3)
683684

684685
def test_empty_keyword(self):

Python/getargs.c

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,7 +1584,7 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs)
15841584
}
15851585
if (!_PyDict_HasOnlyStringKeys(kwargs)) {
15861586
PyErr_SetString(PyExc_TypeError,
1587-
"keyword arguments must be strings");
1587+
"keywords must be strings");
15881588
return 0;
15891589
}
15901590
return 1;
@@ -1655,7 +1655,7 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
16551655
nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs);
16561656
if (nargs + nkwargs > len) {
16571657
PyErr_Format(PyExc_TypeError,
1658-
"%s%s takes at most %d argument%s (%zd given)",
1658+
"%.200s%s takes at most %d argument%s (%zd given)",
16591659
(fname == NULL) ? "function" : fname,
16601660
(fname == NULL) ? "" : "()",
16611661
len,
@@ -1705,8 +1705,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
17051705
}
17061706
if (max < nargs) {
17071707
PyErr_Format(PyExc_TypeError,
1708-
"Function takes %s %d positional arguments"
1708+
"%.200s%s takes %s %d positional arguments"
17091709
" (%d given)",
1710+
(fname == NULL) ? "function" : fname,
1711+
(fname == NULL) ? "" : "()",
17101712
(min != INT_MAX) ? "at most" : "exactly",
17111713
max, nargs);
17121714
return cleanreturn(0, &freelist);
@@ -1752,8 +1754,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
17521754
* or the end of the format. */
17531755
}
17541756
else {
1755-
PyErr_Format(PyExc_TypeError, "Required argument "
1756-
"'%s' (pos %d) not found",
1757+
PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
1758+
"argument '%s' (pos %d)",
1759+
(fname == NULL) ? "function" : fname,
1760+
(fname == NULL) ? "" : "()",
17571761
kwlist[i], i+1);
17581762
return cleanreturn(0, &freelist);
17591763
}
@@ -1779,8 +1783,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
17791783

17801784
if (skip) {
17811785
PyErr_Format(PyExc_TypeError,
1782-
"Function takes %s %d positional arguments"
1786+
"%.200s%s takes %s %d positional arguments"
17831787
" (%d given)",
1788+
(fname == NULL) ? "function" : fname,
1789+
(fname == NULL) ? "" : "()",
17841790
(Py_MIN(pos, min) < i) ? "at least" : "exactly",
17851791
Py_MIN(pos, min), nargs);
17861792
return cleanreturn(0, &freelist);
@@ -1802,8 +1808,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
18021808
if (current_arg) {
18031809
/* arg present in tuple and in dict */
18041810
PyErr_Format(PyExc_TypeError,
1805-
"Argument given by name ('%s') "
1811+
"argument for %.200s%s given by name ('%s') "
18061812
"and position (%d)",
1813+
(fname == NULL) ? "function" : fname,
1814+
(fname == NULL) ? "" : "()",
18071815
kwlist[i], i+1);
18081816
return cleanreturn(0, &freelist);
18091817
}
@@ -1826,8 +1834,10 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
18261834
if (!match) {
18271835
PyErr_Format(PyExc_TypeError,
18281836
"'%U' is an invalid keyword "
1829-
"argument for this function",
1830-
key);
1837+
"argument for %.200s%s",
1838+
key,
1839+
(fname == NULL) ? "this function" : fname,
1840+
(fname == NULL) ? "" : "()");
18311841
return cleanreturn(0, &freelist);
18321842
}
18331843
}
@@ -2060,7 +2070,7 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
20602070
}
20612071
if (nargs + nkwargs > len) {
20622072
PyErr_Format(PyExc_TypeError,
2063-
"%s%s takes at most %d argument%s (%zd given)",
2073+
"%.200s%s takes at most %d argument%s (%zd given)",
20642074
(parser->fname == NULL) ? "function" : parser->fname,
20652075
(parser->fname == NULL) ? "" : "()",
20662076
len,
@@ -2070,7 +2080,9 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
20702080
}
20712081
if (parser->max < nargs) {
20722082
PyErr_Format(PyExc_TypeError,
2073-
"Function takes %s %d positional arguments (%d given)",
2083+
"%200s%s takes %s %d positional arguments (%d given)",
2084+
(parser->fname == NULL) ? "function" : parser->fname,
2085+
(parser->fname == NULL) ? "" : "()",
20742086
(parser->min != INT_MAX) ? "at most" : "exactly",
20752087
parser->max, nargs);
20762088
return cleanreturn(0, &freelist);
@@ -2115,15 +2127,19 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
21152127
if (i < pos) {
21162128
Py_ssize_t min = Py_MIN(pos, parser->min);
21172129
PyErr_Format(PyExc_TypeError,
2118-
"Function takes %s %d positional arguments"
2130+
"%.200s%s takes %s %d positional arguments"
21192131
" (%d given)",
2132+
(parser->fname == NULL) ? "function" : parser->fname,
2133+
(parser->fname == NULL) ? "" : "()",
21202134
min < parser->max ? "at least" : "exactly",
21212135
min, nargs);
21222136
}
21232137
else {
21242138
keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
2125-
PyErr_Format(PyExc_TypeError, "Required argument "
2126-
"'%U' (pos %d) not found",
2139+
PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
2140+
"argument '%U' (pos %d)",
2141+
(parser->fname == NULL) ? "function" : parser->fname,
2142+
(parser->fname == NULL) ? "" : "()",
21272143
keyword, i+1);
21282144
}
21292145
return cleanreturn(0, &freelist);
@@ -2153,8 +2169,10 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
21532169
if (current_arg) {
21542170
/* arg present in tuple and in dict */
21552171
PyErr_Format(PyExc_TypeError,
2156-
"Argument given by name ('%U') "
2172+
"argument for %.200s%s given by name ('%U') "
21572173
"and position (%d)",
2174+
(parser->fname == NULL) ? "function" : parser->fname,
2175+
(parser->fname == NULL) ? "" : "()",
21582176
keyword, i+1);
21592177
return cleanreturn(0, &freelist);
21602178
}
@@ -2184,8 +2202,10 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
21842202
if (!match) {
21852203
PyErr_Format(PyExc_TypeError,
21862204
"'%U' is an invalid keyword "
2187-
"argument for this function",
2188-
keyword);
2205+
"argument for %.200s%s",
2206+
keyword,
2207+
(parser->fname == NULL) ? "this function" : parser->fname,
2208+
(parser->fname == NULL) ? "" : "()");
21892209
}
21902210
return cleanreturn(0, &freelist);
21912211
}
@@ -2365,7 +2385,7 @@ unpack_stack(PyObject **args, Py_ssize_t nargs, const char *name,
23652385
if (name != NULL)
23662386
PyErr_Format(
23672387
PyExc_TypeError,
2368-
"%s expected %s%zd arguments, got %zd",
2388+
"%.200s expected %s%zd arguments, got %zd",
23692389
name, (min == max ? "" : "at least "), min, nargs);
23702390
else
23712391
PyErr_Format(
@@ -2384,7 +2404,7 @@ unpack_stack(PyObject **args, Py_ssize_t nargs, const char *name,
23842404
if (name != NULL)
23852405
PyErr_Format(
23862406
PyExc_TypeError,
2387-
"%s expected %s%zd arguments, got %zd",
2407+
"%.200s expected %s%zd arguments, got %zd",
23882408
name, (min == max ? "" : "at most "), max, nargs);
23892409
else
23902410
PyErr_Format(
@@ -2469,7 +2489,7 @@ _PyArg_NoKeywords(const char *funcname, PyObject *kwargs)
24692489
return 1;
24702490
}
24712491

2472-
PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments",
2492+
PyErr_Format(PyExc_TypeError, "%.200s does not take keyword arguments",
24732493
funcname);
24742494
return 0;
24752495
}
@@ -2486,7 +2506,7 @@ _PyArg_NoStackKeywords(const char *funcname, PyObject *kwnames)
24862506
return 1;
24872507
}
24882508

2489-
PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments",
2509+
PyErr_Format(PyExc_TypeError, "%.200s does not take keyword arguments",
24902510
funcname);
24912511
return 0;
24922512
}
@@ -2504,7 +2524,7 @@ _PyArg_NoPositional(const char *funcname, PyObject *args)
25042524
if (PyTuple_GET_SIZE(args) == 0)
25052525
return 1;
25062526

2507-
PyErr_Format(PyExc_TypeError, "%s does not take positional arguments",
2527+
PyErr_Format(PyExc_TypeError, "%.200s does not take positional arguments",
25082528
funcname);
25092529
return 0;
25102530
}

0 commit comments

Comments
 (0)