Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 2057970

Browse files
committed
This patch makes sure that the function name always appears in the error
message, and tries to make the messages more consistent and helpful when the wrong number of arguments or duplicate keyword arguments are supplied. Comes with more tests for test_extcall.py and and an update to an error message in test/output/test_pyexpat.
1 parent 1ff08b1 commit 2057970

5 files changed

Lines changed: 205 additions & 66 deletions

File tree

Lib/test/output/test_extcall

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ test_extcall
99
(1, 2, 3) {'b': 5, 'a': 4}
1010
(1, 2, 3, 4, 5) {'b': 7, 'a': 6}
1111
(1, 2, 3, 6, 7) {'y': 5, 'b': 9, 'x': 4, 'a': 8}
12-
TypeError: not enough arguments to g(); expected 1, got 0
13-
TypeError: not enough arguments to g(); expected 1, got 0
14-
TypeError: not enough arguments to g(); expected 1, got 0
12+
TypeError: g() takes at least 1 argument (0 given)
13+
TypeError: g() takes at least 1 argument (0 given)
14+
TypeError: g() takes at least 1 argument (0 given)
1515
1 () {}
1616
1 (2,) {}
1717
1 (2, 3) {}
@@ -20,14 +20,89 @@ TypeError: not enough arguments to g(); expected 1, got 0
2020
1 () {'d': 4, 'b': 2, 'c': 3, 'a': 1}
2121
{'b': 2, 'c': 3, 'a': 1}
2222
{'b': 2, 'c': 3, 'a': 1}
23-
keyword parameter 'x' redefined in call to g()
24-
keyword parameter 'b' redefined in function call
25-
keywords must be strings
23+
g() got multiple values for keyword argument 'x'
24+
g() got multiple values for keyword argument 'b'
25+
f() keywords must be strings
2626
h() got an unexpected keyword argument 'e'
27-
* argument must be a sequence
28-
** argument must be a dictionary
27+
h() argument after * must be a sequence
28+
h() argument after ** must be a dictionary
2929
3 512 1
3030
3
3131
3
32-
unbound method must be called with instance as first argument
33-
unbound method must be called with instance as first argument
32+
unbound method method() must be called with instance as first argument
33+
unbound method method() must be called with instance as first argument
34+
za () {} -> za() takes exactly 1 argument (0 given)
35+
za () {'a': 'aa'} -> ok za aa B D E V a
36+
za () {'d': 'dd'} -> za() got an unexpected keyword argument 'd'
37+
za () {'d': 'dd', 'a': 'aa'} -> za() got an unexpected keyword argument 'd'
38+
za () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> za() got an unexpected keyword argument 'd'
39+
za (1, 2) {} -> za() takes exactly 1 argument (2 given)
40+
za (1, 2) {'a': 'aa'} -> za() takes exactly 1 non-keyword argument (2 given)
41+
za (1, 2) {'d': 'dd'} -> za() takes exactly 1 non-keyword argument (2 given)
42+
za (1, 2) {'d': 'dd', 'a': 'aa'} -> za() takes exactly 1 non-keyword argument (2 given)
43+
za (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> za() takes exactly 1 non-keyword argument (2 given)
44+
za (1, 2, 3, 4, 5) {} -> za() takes exactly 1 argument (5 given)
45+
za (1, 2, 3, 4, 5) {'a': 'aa'} -> za() takes exactly 1 non-keyword argument (5 given)
46+
za (1, 2, 3, 4, 5) {'d': 'dd'} -> za() takes exactly 1 non-keyword argument (5 given)
47+
za (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> za() takes exactly 1 non-keyword argument (5 given)
48+
za (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> za() takes exactly 1 non-keyword argument (5 given)
49+
zade () {} -> zade() takes at least 1 argument (0 given)
50+
zade () {'a': 'aa'} -> ok zade aa B d e V a
51+
zade () {'d': 'dd'} -> zade() takes at least 1 non-keyword argument (0 given)
52+
zade () {'d': 'dd', 'a': 'aa'} -> ok zade aa B dd e V d
53+
zade () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zade() got an unexpected keyword argument 'b'
54+
zade (1, 2) {} -> ok zade 1 B 2 e V e
55+
zade (1, 2) {'a': 'aa'} -> zade() got multiple values for keyword argument 'a'
56+
zade (1, 2) {'d': 'dd'} -> zade() got multiple values for keyword argument 'd'
57+
zade (1, 2) {'d': 'dd', 'a': 'aa'} -> zade() got multiple values for keyword argument 'd'
58+
zade (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zade() got multiple values for keyword argument 'd'
59+
zade (1, 2, 3, 4, 5) {} -> zade() takes at most 3 arguments (5 given)
60+
zade (1, 2, 3, 4, 5) {'a': 'aa'} -> zade() takes at most 3 non-keyword arguments (5 given)
61+
zade (1, 2, 3, 4, 5) {'d': 'dd'} -> zade() takes at most 3 non-keyword arguments (5 given)
62+
zade (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> zade() takes at most 3 non-keyword arguments (5 given)
63+
zade (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zade() takes at most 3 non-keyword arguments (5 given)
64+
zabk () {} -> zabk() takes exactly 2 arguments (0 given)
65+
zabk () {'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (1 given)
66+
zabk () {'d': 'dd'} -> zabk() takes exactly 2 non-keyword arguments (0 given)
67+
zabk () {'d': 'dd', 'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (1 given)
68+
zabk () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> ok zabk aa bb D E V {'d': 'dd', 'e': 'ee'}
69+
zabk (1, 2) {} -> ok zabk 1 2 D E V {}
70+
zabk (1, 2) {'a': 'aa'} -> zabk() got multiple values for keyword argument 'a'
71+
zabk (1, 2) {'d': 'dd'} -> ok zabk 1 2 D E V {'d': 'dd'}
72+
zabk (1, 2) {'d': 'dd', 'a': 'aa'} -> zabk() got multiple values for keyword argument 'a'
73+
zabk (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabk() got multiple values for keyword argument 'b'
74+
zabk (1, 2, 3, 4, 5) {} -> zabk() takes exactly 2 arguments (5 given)
75+
zabk (1, 2, 3, 4, 5) {'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (5 given)
76+
zabk (1, 2, 3, 4, 5) {'d': 'dd'} -> zabk() takes exactly 2 non-keyword arguments (5 given)
77+
zabk (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (5 given)
78+
zabk (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (5 given)
79+
zabdv () {} -> zabdv() takes at least 2 arguments (0 given)
80+
zabdv () {'a': 'aa'} -> zabdv() takes at least 2 non-keyword arguments (1 given)
81+
zabdv () {'d': 'dd'} -> zabdv() takes at least 2 non-keyword arguments (0 given)
82+
zabdv () {'d': 'dd', 'a': 'aa'} -> zabdv() takes at least 2 non-keyword arguments (1 given)
83+
zabdv () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdv() got an unexpected keyword argument 'e'
84+
zabdv (1, 2) {} -> ok zabdv 1 2 d E () e
85+
zabdv (1, 2) {'a': 'aa'} -> zabdv() got multiple values for keyword argument 'a'
86+
zabdv (1, 2) {'d': 'dd'} -> ok zabdv 1 2 dd E () d
87+
zabdv (1, 2) {'d': 'dd', 'a': 'aa'} -> zabdv() got multiple values for keyword argument 'a'
88+
zabdv (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdv() got an unexpected keyword argument 'e'
89+
zabdv (1, 2, 3, 4, 5) {} -> ok zabdv 1 2 3 E (4, 5) e
90+
zabdv (1, 2, 3, 4, 5) {'a': 'aa'} -> zabdv() got multiple values for keyword argument 'a'
91+
zabdv (1, 2, 3, 4, 5) {'d': 'dd'} -> zabdv() got multiple values for keyword argument 'd'
92+
zabdv (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> zabdv() got multiple values for keyword argument 'd'
93+
zabdv (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdv() got multiple values for keyword argument 'd'
94+
zabdevk () {} -> zabdevk() takes at least 2 arguments (0 given)
95+
zabdevk () {'a': 'aa'} -> zabdevk() takes at least 2 non-keyword arguments (1 given)
96+
zabdevk () {'d': 'dd'} -> zabdevk() takes at least 2 non-keyword arguments (0 given)
97+
zabdevk () {'d': 'dd', 'a': 'aa'} -> zabdevk() takes at least 2 non-keyword arguments (1 given)
98+
zabdevk () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> ok zabdevk aa bb dd ee () {}
99+
zabdevk (1, 2) {} -> ok zabdevk 1 2 d e () {}
100+
zabdevk (1, 2) {'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'a'
101+
zabdevk (1, 2) {'d': 'dd'} -> ok zabdevk 1 2 dd e () {}
102+
zabdevk (1, 2) {'d': 'dd', 'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'a'
103+
zabdevk (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'b'
104+
zabdevk (1, 2, 3, 4, 5) {} -> ok zabdevk 1 2 3 4 (5,) {}
105+
zabdevk (1, 2, 3, 4, 5) {'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'a'
106+
zabdevk (1, 2, 3, 4, 5) {'d': 'dd'} -> zabdevk() got multiple values for keyword argument 'd'
107+
zabdevk (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'd'
108+
zabdevk (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'd'

Lib/test/output/test_pyexpat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ End element:
9797
Testing constructor for proper handling of namespace_separator values:
9898
Legal values tested o.k.
9999
Caught expected TypeError:
100-
ParserCreate, argument 2: expected string or None, int found
100+
ParserCreate() argument 2 must be string or None, not int
101101
Caught expected ValueError:
102102
namespace_separator must be one character, omitted, or None
103103
Caught expected ValueError:

Lib/test/test_extcall.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from UserList import UserList
22
from test_support import TestFailed
3+
import string
34

45
def f(*a, **k):
56
print a, k
@@ -172,3 +173,32 @@ def method(self, arg1, arg2):
172173
pass
173174
else:
174175
raise TestFailed, 'expected TypeError; no exception raised'
176+
177+
a, b, d, e, v, k = 'A', 'B', 'D', 'E', 'V', 'K'
178+
funcs = []
179+
maxargs = {}
180+
for args in ['', 'a', 'ab']:
181+
for defargs in ['', 'd', 'de']:
182+
for vararg in ['', 'v']:
183+
for kwarg in ['', 'k']:
184+
name = 'z' + args + defargs + vararg + kwarg
185+
arglist = list(args) + map(
186+
lambda x: '%s="%s"' % (x, x), defargs)
187+
if vararg: arglist.append('*' + vararg)
188+
if kwarg: arglist.append('**' + kwarg)
189+
decl = 'def %s(%s): print "ok %s", a, b, d, e, v, k' % (
190+
name, string.join(arglist, ', '), name)
191+
exec(decl)
192+
func = eval(name)
193+
funcs.append(func)
194+
maxargs[func] = len(args + defargs)
195+
196+
for name in ['za', 'zade', 'zabk', 'zabdv', 'zabdevk']:
197+
func = eval(name)
198+
for args in [(), (1, 2), (1, 2, 3, 4, 5)]:
199+
for kwargs in ['', 'a', 'd', 'ad', 'abde']:
200+
kwdict = {}
201+
for k in kwargs: kwdict[k] = k + k
202+
print func.func_name, args, kwdict, '->',
203+
try: apply(func, args, kwdict)
204+
except TypeError, err: print err

Python/ceval.c

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ static PyObject *fast_function(PyObject *, PyObject ***, int, int, int);
4848
static PyObject *fast_cfunction(PyObject *, PyObject ***, int);
4949
static PyObject *do_call(PyObject *, PyObject ***, int, int);
5050
static PyObject *ext_do_call(PyObject *, PyObject ***, int, int, int);
51-
static PyObject *update_keyword_args(PyObject *, int, PyObject ***);
52-
static PyObject *update_star_args(int, int, PyObject *, PyObject ***);
51+
static PyObject *update_keyword_args(PyObject *, int, PyObject ***, PyObject *);
52+
static PyObject *update_star_args(int, int, PyObject *, PyObject ***);
5353
static PyObject *load_args(PyObject ***, int);
5454
#define CALL_FLAG_VAR 1
5555
#define CALL_FLAG_KW 2
@@ -451,10 +451,14 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
451451
if (argcount > co->co_argcount) {
452452
if (!(co->co_flags & CO_VARARGS)) {
453453
PyErr_Format(PyExc_TypeError,
454-
"too many arguments to %s(); "
455-
"expected %d, got %d",
454+
"%.200s() takes %s %d "
455+
"%sargument%s (%d given)",
456456
PyString_AsString(co->co_name),
457-
co->co_argcount, argcount);
457+
defcount ? "at most" : "exactly",
458+
co->co_argcount,
459+
kwcount ? "non-keyword " : "",
460+
co->co_argcount == 1 ? "" : "s",
461+
argcount);
458462
goto fail;
459463
}
460464
n = co->co_argcount;
@@ -480,8 +484,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
480484
PyObject *value = kws[2*i + 1];
481485
int j;
482486
if (keyword == NULL || !PyString_Check(keyword)) {
483-
PyErr_SetString(PyExc_TypeError,
484-
"keywords must be strings");
487+
PyErr_Format(PyExc_TypeError,
488+
"%.200s() keywords must be strings",
489+
PyString_AsString(co->co_name));
485490
goto fail;
486491
}
487492
/* XXX slow -- speed up using dictionary? */
@@ -508,10 +513,11 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
508513
else {
509514
if (GETLOCAL(j) != NULL) {
510515
PyErr_Format(PyExc_TypeError,
511-
"keyword parameter '%.400s' "
512-
"redefined in call to %.200s()",
513-
PyString_AsString(keyword),
514-
PyString_AsString(co->co_name));
516+
"%.200s() got multiple "
517+
"values for keyword "
518+
"argument '%.400s'",
519+
PyString_AsString(co->co_name),
520+
PyString_AsString(keyword));
515521
goto fail;
516522
}
517523
Py_INCREF(value);
@@ -523,10 +529,14 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
523529
for (i = argcount; i < m; i++) {
524530
if (GETLOCAL(i) == NULL) {
525531
PyErr_Format(PyExc_TypeError,
526-
"not enough arguments to "
527-
"%.200s(); expected %d, got %d",
532+
"%.200s() takes %s %d "
533+
"%sargument%s (%d given)",
528534
PyString_AsString(co->co_name),
529-
m, i);
535+
((co->co_flags & CO_VARARGS) ||
536+
defcount) ? "at least"
537+
: "exactly",
538+
m, kwcount ? "non-keyword " : "",
539+
m == 1 ? "" : "s", i);
530540
goto fail;
531541
}
532542
}
@@ -546,8 +556,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
546556
else {
547557
if (argcount > 0 || kwcount > 0) {
548558
PyErr_Format(PyExc_TypeError,
549-
"%.200s() expected no arguments",
550-
PyString_AsString(co->co_name));
559+
"%.200s() takes no arguments (%d given)",
560+
PyString_AsString(co->co_name),
561+
argcount + kwcount);
551562
goto fail;
552563
}
553564
}
@@ -2669,8 +2680,12 @@ call_method(PyObject *func, PyObject *arg, PyObject *kw)
26692680
&& PyClass_IsSubclass((PyObject *)
26702681
(((PyInstanceObject *)self)->in_class),
26712682
class))) {
2672-
PyErr_SetString(PyExc_TypeError,
2673-
"unbound method must be called with instance as first argument");
2683+
PyObject* fn = ((PyFunctionObject*) func)->func_name;
2684+
PyErr_Format(PyExc_TypeError,
2685+
"unbound method %s%smust be "
2686+
"called with instance as first argument",
2687+
fn ? PyString_AsString(fn) : "",
2688+
fn ? "() " : "");
26742689
return NULL;
26752690
}
26762691
Py_INCREF(arg);
@@ -2793,7 +2808,8 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
27932808
}
27942809

27952810
static PyObject *
2796-
update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack)
2811+
update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack,
2812+
PyObject *func)
27972813
{
27982814
PyObject *kwdict = NULL;
27992815
if (orig_kwdict == NULL)
@@ -2809,10 +2825,12 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack)
28092825
PyObject *value = EXT_POP(*pp_stack);
28102826
PyObject *key = EXT_POP(*pp_stack);
28112827
if (PyDict_GetItem(kwdict, key) != NULL) {
2812-
PyErr_Format(PyExc_TypeError,
2813-
"keyword parameter '%.400s' "
2814-
"redefined in function call",
2815-
PyString_AsString(key));
2828+
PyObject* fn = ((PyFunctionObject*) func)->func_name;
2829+
PyErr_Format(PyExc_TypeError,
2830+
"%.200s%s got multiple values "
2831+
"for keyword argument '%.400s'",
2832+
fn ? PyString_AsString(fn) : "function",
2833+
fn ? "()" : "", PyString_AsString(key));
28162834
Py_DECREF(key);
28172835
Py_DECREF(value);
28182836
Py_DECREF(kwdict);
@@ -2877,7 +2895,7 @@ do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
28772895
PyObject *result = NULL;
28782896

28792897
if (nk > 0) {
2880-
kwdict = update_keyword_args(NULL, nk, pp_stack);
2898+
kwdict = update_keyword_args(NULL, nk, pp_stack, func);
28812899
if (kwdict == NULL)
28822900
goto call_fail;
28832901
}
@@ -2903,8 +2921,11 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
29032921
if (flags & CALL_FLAG_KW) {
29042922
kwdict = EXT_POP(*pp_stack);
29052923
if (!(kwdict && PyDict_Check(kwdict))) {
2906-
PyErr_SetString(PyExc_TypeError,
2907-
"** argument must be a dictionary");
2924+
PyObject* fn = ((PyFunctionObject*) func)->func_name;
2925+
PyErr_Format(PyExc_TypeError,
2926+
"%s%s argument after ** must be a dictionary",
2927+
fn ? PyString_AsString(fn) : "function",
2928+
fn ? "()" : "");
29082929
goto ext_call_fail;
29092930
}
29102931
}
@@ -2915,8 +2936,12 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
29152936
t = PySequence_Tuple(stararg);
29162937
if (t == NULL) {
29172938
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
2918-
PyErr_SetString(PyExc_TypeError,
2919-
"* argument must be a sequence");
2939+
PyObject* fn =
2940+
((PyFunctionObject*) func)->func_name;
2941+
PyErr_Format(PyExc_TypeError,
2942+
"%s%s argument after * must be a sequence",
2943+
fn ? PyString_AsString(fn) : "function",
2944+
fn ? "()" : "");
29202945
}
29212946
goto ext_call_fail;
29222947
}
@@ -2926,7 +2951,7 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
29262951
nstar = PyTuple_GET_SIZE(stararg);
29272952
}
29282953
if (nk > 0) {
2929-
kwdict = update_keyword_args(kwdict, nk, pp_stack);
2954+
kwdict = update_keyword_args(kwdict, nk, pp_stack, func);
29302955
if (kwdict == NULL)
29312956
goto ext_call_fail;
29322957
}

0 commit comments

Comments
 (0)