Commit 1e1ac26e authored by Ka-Ping Yee's avatar Ka-Ping Yee

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.
parent 082c9972
...@@ -9,9 +9,9 @@ test_extcall ...@@ -9,9 +9,9 @@ test_extcall
(1, 2, 3) {'b': 5, 'a': 4} (1, 2, 3) {'b': 5, 'a': 4}
(1, 2, 3, 4, 5) {'b': 7, 'a': 6} (1, 2, 3, 4, 5) {'b': 7, 'a': 6}
(1, 2, 3, 6, 7) {'y': 5, 'b': 9, 'x': 4, 'a': 8} (1, 2, 3, 6, 7) {'y': 5, 'b': 9, 'x': 4, 'a': 8}
TypeError: not enough arguments to g(); expected 1, got 0 TypeError: g() takes at least 1 argument (0 given)
TypeError: not enough arguments to g(); expected 1, got 0 TypeError: g() takes at least 1 argument (0 given)
TypeError: not enough arguments to g(); expected 1, got 0 TypeError: g() takes at least 1 argument (0 given)
1 () {} 1 () {}
1 (2,) {} 1 (2,) {}
1 (2, 3) {} 1 (2, 3) {}
...@@ -20,14 +20,89 @@ TypeError: not enough arguments to g(); expected 1, got 0 ...@@ -20,14 +20,89 @@ TypeError: not enough arguments to g(); expected 1, got 0
1 () {'d': 4, 'b': 2, 'c': 3, 'a': 1} 1 () {'d': 4, 'b': 2, 'c': 3, 'a': 1}
{'b': 2, 'c': 3, 'a': 1} {'b': 2, 'c': 3, 'a': 1}
{'b': 2, 'c': 3, 'a': 1} {'b': 2, 'c': 3, 'a': 1}
keyword parameter 'x' redefined in call to g() g() got multiple values for keyword argument 'x'
keyword parameter 'b' redefined in function call g() got multiple values for keyword argument 'b'
keywords must be strings f() keywords must be strings
h() got an unexpected keyword argument 'e' h() got an unexpected keyword argument 'e'
* argument must be a sequence h() argument after * must be a sequence
** argument must be a dictionary h() argument after ** must be a dictionary
3 512 1 3 512 1
3 3
3 3
unbound method must be called with instance as first argument unbound method method() must be called with instance as first argument
unbound method must be called with instance as first argument unbound method method() must be called with instance as first argument
za () {} -> za() takes exactly 1 argument (0 given)
za () {'a': 'aa'} -> ok za aa B D E V a
za () {'d': 'dd'} -> za() got an unexpected keyword argument 'd'
za () {'d': 'dd', 'a': 'aa'} -> za() got an unexpected keyword argument 'd'
za () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> za() got an unexpected keyword argument 'd'
za (1, 2) {} -> za() takes exactly 1 argument (2 given)
za (1, 2) {'a': 'aa'} -> za() takes exactly 1 non-keyword argument (2 given)
za (1, 2) {'d': 'dd'} -> za() takes exactly 1 non-keyword argument (2 given)
za (1, 2) {'d': 'dd', 'a': 'aa'} -> za() takes exactly 1 non-keyword argument (2 given)
za (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> za() takes exactly 1 non-keyword argument (2 given)
za (1, 2, 3, 4, 5) {} -> za() takes exactly 1 argument (5 given)
za (1, 2, 3, 4, 5) {'a': 'aa'} -> za() takes exactly 1 non-keyword argument (5 given)
za (1, 2, 3, 4, 5) {'d': 'dd'} -> za() takes exactly 1 non-keyword argument (5 given)
za (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> za() takes exactly 1 non-keyword argument (5 given)
za (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> za() takes exactly 1 non-keyword argument (5 given)
zade () {} -> zade() takes at least 1 argument (0 given)
zade () {'a': 'aa'} -> ok zade aa B d e V a
zade () {'d': 'dd'} -> zade() takes at least 1 non-keyword argument (0 given)
zade () {'d': 'dd', 'a': 'aa'} -> ok zade aa B dd e V d
zade () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zade() got an unexpected keyword argument 'b'
zade (1, 2) {} -> ok zade 1 B 2 e V e
zade (1, 2) {'a': 'aa'} -> zade() got multiple values for keyword argument 'a'
zade (1, 2) {'d': 'dd'} -> zade() got multiple values for keyword argument 'd'
zade (1, 2) {'d': 'dd', 'a': 'aa'} -> zade() got multiple values for keyword argument 'd'
zade (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zade() got multiple values for keyword argument 'd'
zade (1, 2, 3, 4, 5) {} -> zade() takes at most 3 arguments (5 given)
zade (1, 2, 3, 4, 5) {'a': 'aa'} -> zade() takes at most 3 non-keyword arguments (5 given)
zade (1, 2, 3, 4, 5) {'d': 'dd'} -> zade() takes at most 3 non-keyword arguments (5 given)
zade (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> zade() takes at most 3 non-keyword arguments (5 given)
zade (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zade() takes at most 3 non-keyword arguments (5 given)
zabk () {} -> zabk() takes exactly 2 arguments (0 given)
zabk () {'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (1 given)
zabk () {'d': 'dd'} -> zabk() takes exactly 2 non-keyword arguments (0 given)
zabk () {'d': 'dd', 'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (1 given)
zabk () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> ok zabk aa bb D E V {'d': 'dd', 'e': 'ee'}
zabk (1, 2) {} -> ok zabk 1 2 D E V {}
zabk (1, 2) {'a': 'aa'} -> zabk() got multiple values for keyword argument 'a'
zabk (1, 2) {'d': 'dd'} -> ok zabk 1 2 D E V {'d': 'dd'}
zabk (1, 2) {'d': 'dd', 'a': 'aa'} -> zabk() got multiple values for keyword argument 'a'
zabk (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabk() got multiple values for keyword argument 'b'
zabk (1, 2, 3, 4, 5) {} -> zabk() takes exactly 2 arguments (5 given)
zabk (1, 2, 3, 4, 5) {'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (5 given)
zabk (1, 2, 3, 4, 5) {'d': 'dd'} -> zabk() takes exactly 2 non-keyword arguments (5 given)
zabk (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (5 given)
zabk (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabk() takes exactly 2 non-keyword arguments (5 given)
zabdv () {} -> zabdv() takes at least 2 arguments (0 given)
zabdv () {'a': 'aa'} -> zabdv() takes at least 2 non-keyword arguments (1 given)
zabdv () {'d': 'dd'} -> zabdv() takes at least 2 non-keyword arguments (0 given)
zabdv () {'d': 'dd', 'a': 'aa'} -> zabdv() takes at least 2 non-keyword arguments (1 given)
zabdv () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdv() got an unexpected keyword argument 'e'
zabdv (1, 2) {} -> ok zabdv 1 2 d E () e
zabdv (1, 2) {'a': 'aa'} -> zabdv() got multiple values for keyword argument 'a'
zabdv (1, 2) {'d': 'dd'} -> ok zabdv 1 2 dd E () d
zabdv (1, 2) {'d': 'dd', 'a': 'aa'} -> zabdv() got multiple values for keyword argument 'a'
zabdv (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdv() got an unexpected keyword argument 'e'
zabdv (1, 2, 3, 4, 5) {} -> ok zabdv 1 2 3 E (4, 5) e
zabdv (1, 2, 3, 4, 5) {'a': 'aa'} -> zabdv() got multiple values for keyword argument 'a'
zabdv (1, 2, 3, 4, 5) {'d': 'dd'} -> zabdv() got multiple values for keyword argument 'd'
zabdv (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> zabdv() got multiple values for keyword argument 'd'
zabdv (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdv() got multiple values for keyword argument 'd'
zabdevk () {} -> zabdevk() takes at least 2 arguments (0 given)
zabdevk () {'a': 'aa'} -> zabdevk() takes at least 2 non-keyword arguments (1 given)
zabdevk () {'d': 'dd'} -> zabdevk() takes at least 2 non-keyword arguments (0 given)
zabdevk () {'d': 'dd', 'a': 'aa'} -> zabdevk() takes at least 2 non-keyword arguments (1 given)
zabdevk () {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> ok zabdevk aa bb dd ee () {}
zabdevk (1, 2) {} -> ok zabdevk 1 2 d e () {}
zabdevk (1, 2) {'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'a'
zabdevk (1, 2) {'d': 'dd'} -> ok zabdevk 1 2 dd e () {}
zabdevk (1, 2) {'d': 'dd', 'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'a'
zabdevk (1, 2) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'b'
zabdevk (1, 2, 3, 4, 5) {} -> ok zabdevk 1 2 3 4 (5,) {}
zabdevk (1, 2, 3, 4, 5) {'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'a'
zabdevk (1, 2, 3, 4, 5) {'d': 'dd'} -> zabdevk() got multiple values for keyword argument 'd'
zabdevk (1, 2, 3, 4, 5) {'d': 'dd', 'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'd'
zabdevk (1, 2, 3, 4, 5) {'d': 'dd', 'e': 'ee', 'b': 'bb', 'a': 'aa'} -> zabdevk() got multiple values for keyword argument 'd'
...@@ -97,7 +97,7 @@ End element: ...@@ -97,7 +97,7 @@ End element:
Testing constructor for proper handling of namespace_separator values: Testing constructor for proper handling of namespace_separator values:
Legal values tested o.k. Legal values tested o.k.
Caught expected TypeError: Caught expected TypeError:
ParserCreate, argument 2: expected string or None, int found ParserCreate() argument 2 must be string or None, not int
Caught expected ValueError: Caught expected ValueError:
namespace_separator must be one character, omitted, or None namespace_separator must be one character, omitted, or None
Caught expected ValueError: Caught expected ValueError:
......
from UserList import UserList from UserList import UserList
from test_support import TestFailed from test_support import TestFailed
import string
def f(*a, **k): def f(*a, **k):
print a, k print a, k
...@@ -172,3 +173,32 @@ except TypeError: ...@@ -172,3 +173,32 @@ except TypeError:
pass pass
else: else:
raise TestFailed, 'expected TypeError; no exception raised' raise TestFailed, 'expected TypeError; no exception raised'
a, b, d, e, v, k = 'A', 'B', 'D', 'E', 'V', 'K'
funcs = []
maxargs = {}
for args in ['', 'a', 'ab']:
for defargs in ['', 'd', 'de']:
for vararg in ['', 'v']:
for kwarg in ['', 'k']:
name = 'z' + args + defargs + vararg + kwarg
arglist = list(args) + map(
lambda x: '%s="%s"' % (x, x), defargs)
if vararg: arglist.append('*' + vararg)
if kwarg: arglist.append('**' + kwarg)
decl = 'def %s(%s): print "ok %s", a, b, d, e, v, k' % (
name, string.join(arglist, ', '), name)
exec(decl)
func = eval(name)
funcs.append(func)
maxargs[func] = len(args + defargs)
for name in ['za', 'zade', 'zabk', 'zabdv', 'zabdevk']:
func = eval(name)
for args in [(), (1, 2), (1, 2, 3, 4, 5)]:
for kwargs in ['', 'a', 'd', 'ad', 'abde']:
kwdict = {}
for k in kwargs: kwdict[k] = k + k
print func.func_name, args, kwdict, '->',
try: apply(func, args, kwdict)
except TypeError, err: print err
...@@ -48,7 +48,7 @@ static PyObject *fast_function(PyObject *, PyObject ***, int, int, int); ...@@ -48,7 +48,7 @@ static PyObject *fast_function(PyObject *, PyObject ***, int, int, int);
static PyObject *fast_cfunction(PyObject *, PyObject ***, int); static PyObject *fast_cfunction(PyObject *, PyObject ***, int);
static PyObject *do_call(PyObject *, PyObject ***, int, int); static PyObject *do_call(PyObject *, PyObject ***, int, int);
static PyObject *ext_do_call(PyObject *, PyObject ***, int, int, int); static PyObject *ext_do_call(PyObject *, PyObject ***, int, int, int);
static PyObject *update_keyword_args(PyObject *, int, PyObject ***); static PyObject *update_keyword_args(PyObject *, int, PyObject ***, PyObject *);
static PyObject *update_star_args(int, int, PyObject *, PyObject ***); static PyObject *update_star_args(int, int, PyObject *, PyObject ***);
static PyObject *load_args(PyObject ***, int); static PyObject *load_args(PyObject ***, int);
#define CALL_FLAG_VAR 1 #define CALL_FLAG_VAR 1
...@@ -451,10 +451,14 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -451,10 +451,14 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
if (argcount > co->co_argcount) { if (argcount > co->co_argcount) {
if (!(co->co_flags & CO_VARARGS)) { if (!(co->co_flags & CO_VARARGS)) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"too many arguments to %s(); " "%.200s() takes %s %d "
"expected %d, got %d", "%sargument%s (%d given)",
PyString_AsString(co->co_name), PyString_AsString(co->co_name),
co->co_argcount, argcount); defcount ? "at most" : "exactly",
co->co_argcount,
kwcount ? "non-keyword " : "",
co->co_argcount == 1 ? "" : "s",
argcount);
goto fail; goto fail;
} }
n = co->co_argcount; n = co->co_argcount;
...@@ -480,8 +484,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -480,8 +484,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
PyObject *value = kws[2*i + 1]; PyObject *value = kws[2*i + 1];
int j; int j;
if (keyword == NULL || !PyString_Check(keyword)) { if (keyword == NULL || !PyString_Check(keyword)) {
PyErr_SetString(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"keywords must be strings"); "%.200s() keywords must be strings",
PyString_AsString(co->co_name));
goto fail; goto fail;
} }
/* XXX slow -- speed up using dictionary? */ /* XXX slow -- speed up using dictionary? */
...@@ -508,10 +513,11 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -508,10 +513,11 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
else { else {
if (GETLOCAL(j) != NULL) { if (GETLOCAL(j) != NULL) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"keyword parameter '%.400s' " "%.200s() got multiple "
"redefined in call to %.200s()", "values for keyword "
PyString_AsString(keyword), "argument '%.400s'",
PyString_AsString(co->co_name)); PyString_AsString(co->co_name),
PyString_AsString(keyword));
goto fail; goto fail;
} }
Py_INCREF(value); Py_INCREF(value);
...@@ -523,10 +529,14 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -523,10 +529,14 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
for (i = argcount; i < m; i++) { for (i = argcount; i < m; i++) {
if (GETLOCAL(i) == NULL) { if (GETLOCAL(i) == NULL) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"not enough arguments to " "%.200s() takes %s %d "
"%.200s(); expected %d, got %d", "%sargument%s (%d given)",
PyString_AsString(co->co_name), PyString_AsString(co->co_name),
m, i); ((co->co_flags & CO_VARARGS) ||
defcount) ? "at least"
: "exactly",
m, kwcount ? "non-keyword " : "",
m == 1 ? "" : "s", i);
goto fail; goto fail;
} }
} }
...@@ -546,8 +556,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals, ...@@ -546,8 +556,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
else { else {
if (argcount > 0 || kwcount > 0) { if (argcount > 0 || kwcount > 0) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s() expected no arguments", "%.200s() takes no arguments (%d given)",
PyString_AsString(co->co_name)); PyString_AsString(co->co_name),
argcount + kwcount);
goto fail; goto fail;
} }
} }
...@@ -2669,8 +2680,12 @@ call_method(PyObject *func, PyObject *arg, PyObject *kw) ...@@ -2669,8 +2680,12 @@ call_method(PyObject *func, PyObject *arg, PyObject *kw)
&& PyClass_IsSubclass((PyObject *) && PyClass_IsSubclass((PyObject *)
(((PyInstanceObject *)self)->in_class), (((PyInstanceObject *)self)->in_class),
class))) { class))) {
PyErr_SetString(PyExc_TypeError, PyObject* fn = ((PyFunctionObject*) func)->func_name;
"unbound method must be called with instance as first argument"); PyErr_Format(PyExc_TypeError,
"unbound method %s%smust be "
"called with instance as first argument",
fn ? PyString_AsString(fn) : "",
fn ? "() " : "");
return NULL; return NULL;
} }
Py_INCREF(arg); Py_INCREF(arg);
...@@ -2793,7 +2808,8 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) ...@@ -2793,7 +2808,8 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
} }
static PyObject * static PyObject *
update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack) update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack,
PyObject *func)
{ {
PyObject *kwdict = NULL; PyObject *kwdict = NULL;
if (orig_kwdict == NULL) if (orig_kwdict == NULL)
...@@ -2809,10 +2825,12 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack) ...@@ -2809,10 +2825,12 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack)
PyObject *value = EXT_POP(*pp_stack); PyObject *value = EXT_POP(*pp_stack);
PyObject *key = EXT_POP(*pp_stack); PyObject *key = EXT_POP(*pp_stack);
if (PyDict_GetItem(kwdict, key) != NULL) { if (PyDict_GetItem(kwdict, key) != NULL) {
PyObject* fn = ((PyFunctionObject*) func)->func_name;
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"keyword parameter '%.400s' " "%.200s%s got multiple values "
"redefined in function call", "for keyword argument '%.400s'",
PyString_AsString(key)); fn ? PyString_AsString(fn) : "function",
fn ? "()" : "", PyString_AsString(key));
Py_DECREF(key); Py_DECREF(key);
Py_DECREF(value); Py_DECREF(value);
Py_DECREF(kwdict); Py_DECREF(kwdict);
...@@ -2877,7 +2895,7 @@ do_call(PyObject *func, PyObject ***pp_stack, int na, int nk) ...@@ -2877,7 +2895,7 @@ do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
PyObject *result = NULL; PyObject *result = NULL;
if (nk > 0) { if (nk > 0) {
kwdict = update_keyword_args(NULL, nk, pp_stack); kwdict = update_keyword_args(NULL, nk, pp_stack, func);
if (kwdict == NULL) if (kwdict == NULL)
goto call_fail; goto call_fail;
} }
...@@ -2903,8 +2921,11 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk) ...@@ -2903,8 +2921,11 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
if (flags & CALL_FLAG_KW) { if (flags & CALL_FLAG_KW) {
kwdict = EXT_POP(*pp_stack); kwdict = EXT_POP(*pp_stack);
if (!(kwdict && PyDict_Check(kwdict))) { if (!(kwdict && PyDict_Check(kwdict))) {
PyErr_SetString(PyExc_TypeError, PyObject* fn = ((PyFunctionObject*) func)->func_name;
"** argument must be a dictionary"); PyErr_Format(PyExc_TypeError,
"%s%s argument after ** must be a dictionary",
fn ? PyString_AsString(fn) : "function",
fn ? "()" : "");
goto ext_call_fail; goto ext_call_fail;
} }
} }
...@@ -2915,8 +2936,12 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk) ...@@ -2915,8 +2936,12 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
t = PySequence_Tuple(stararg); t = PySequence_Tuple(stararg);
if (t == NULL) { if (t == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) { if (PyErr_ExceptionMatches(PyExc_TypeError)) {
PyErr_SetString(PyExc_TypeError, PyObject* fn =
"* argument must be a sequence"); ((PyFunctionObject*) func)->func_name;
PyErr_Format(PyExc_TypeError,
"%s%s argument after * must be a sequence",
fn ? PyString_AsString(fn) : "function",
fn ? "()" : "");
} }
goto ext_call_fail; goto ext_call_fail;
} }
...@@ -2926,7 +2951,7 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk) ...@@ -2926,7 +2951,7 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
nstar = PyTuple_GET_SIZE(stararg); nstar = PyTuple_GET_SIZE(stararg);
} }
if (nk > 0) { if (nk > 0) {
kwdict = update_keyword_args(kwdict, nk, pp_stack); kwdict = update_keyword_args(kwdict, nk, pp_stack, func);
if (kwdict == NULL) if (kwdict == NULL)
goto ext_call_fail; goto ext_call_fail;
} }
......
...@@ -130,16 +130,18 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat) ...@@ -130,16 +130,18 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
if (max == 0) { if (max == 0) {
if (args == NULL) if (args == NULL)
return 1; return 1;
sprintf(msgbuf, "%s requires no arguments", sprintf(msgbuf, "%s%s takes no arguments",
fname==NULL ? "function" : fname); fname==NULL ? "function" : fname,
fname==NULL ? "" : "()");
PyErr_SetString(PyExc_TypeError, msgbuf); PyErr_SetString(PyExc_TypeError, msgbuf);
return 0; return 0;
} }
else if (min == 1 && max == 1) { else if (min == 1 && max == 1) {
if (args == NULL) { if (args == NULL) {
sprintf(msgbuf, sprintf(msgbuf,
"%s requires at least one argument", "%s%s takes at least one argument",
fname==NULL ? "function" : fname); fname==NULL ? "function" : fname,
fname==NULL ? "" : "()");
PyErr_SetString(PyExc_TypeError, msgbuf); PyErr_SetString(PyExc_TypeError, msgbuf);
return 0; return 0;
} }
...@@ -167,8 +169,9 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat) ...@@ -167,8 +169,9 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
if (len < min || max < len) { if (len < min || max < len) {
if (message == NULL) { if (message == NULL) {
sprintf(msgbuf, sprintf(msgbuf,
"%s requires %s %d argument%s; %d given", "%s%s takes %s %d argument%s (%d given)",
fname==NULL ? "function" : fname, fname==NULL ? "function" : fname,
fname==NULL ? "" : "()",
min==max ? "exactly" min==max ? "exactly"
: len < min ? "at least" : "at most", : len < min ? "at least" : "at most",
len < min ? min : max, len < min ? min : max,
...@@ -213,13 +216,12 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message) ...@@ -213,13 +216,12 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message)
if (PyErr_Occurred()) if (PyErr_Occurred())
return; return;
if (iarg == 0 && message == NULL)
message = msg;
else if (message == NULL) { else if (message == NULL) {
if (fname != NULL) { if (fname != NULL) {
sprintf(p, "%s, ", fname); sprintf(p, "%s() ", fname);
p += strlen(p); p += strlen(p);
} }
if (iarg != 0) {
sprintf(p, "argument %d", iarg); sprintf(p, "argument %d", iarg);
i = 0; i = 0;
p += strlen(p); p += strlen(p);
...@@ -228,7 +230,12 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message) ...@@ -228,7 +230,12 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message)
p += strlen(p); p += strlen(p);
i++; i++;
} }
sprintf(p, ": expected %s found", msg); }
else {
sprintf(p, "argument");
p += strlen(p);
}
sprintf(p, " %s", msg);
message = buf; message = buf;
} }
PyErr_SetString(PyExc_TypeError, message); PyErr_SetString(PyExc_TypeError, message);
...@@ -247,10 +254,9 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message) ...@@ -247,10 +254,9 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message)
*p_va is undefined, *p_va is undefined,
*levels is a 0-terminated list of item numbers, *levels is a 0-terminated list of item numbers,
*msgbuf contains an error message, whose format is: *msgbuf contains an error message, whose format is:
"<typename1>, <typename2>", where: "must be <typename1>, not <typename2>", where:
<typename1> is the name of the expected type, and <typename1> is the name of the expected type, and
<typename2> is the name of the actual type, <typename2> is the name of the actual type,
(so you can surround it by "expected ... found"),
and msgbuf is returned. and msgbuf is returned.
*/ */
...@@ -281,10 +287,11 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels, ...@@ -281,10 +287,11 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
n++; n++;
} }
if (!PySequence_Check(arg)) { if (!PySequence_Check(arg) || PyString_Check(arg)) {
levels[0] = 0; levels[0] = 0;
sprintf(msgbuf, sprintf(msgbuf,
toplevel ? "%d arguments, %s" : "%d-sequence, %s", toplevel ? "expected %d arguments, not %s" :
"must be %d-item sequence, not %s",
n, arg == Py_None ? "None" : arg->ob_type->tp_name); n, arg == Py_None ? "None" : arg->ob_type->tp_name);
return msgbuf; return msgbuf;
} }
...@@ -292,7 +299,8 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels, ...@@ -292,7 +299,8 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
if ((i = PySequence_Size(arg)) != n) { if ((i = PySequence_Size(arg)) != n) {
levels[0] = 0; levels[0] = 0;
sprintf(msgbuf, sprintf(msgbuf,
toplevel ? "%d arguments, %d" : "%d-sequence, %d-sequence", toplevel ? "expected %d arguments, not %d" :
"must be sequence of length %d, not %d",
n, i); n, i);
return msgbuf; return msgbuf;
} }
...@@ -343,14 +351,14 @@ convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels, ...@@ -343,14 +351,14 @@ convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels,
/* Convert a non-tuple argument. Adds to convertsimple1 functionality /* Convert a non-tuple argument. Adds to convertsimple1 functionality
by appending ", <actual argument type>" to error message. */ by formatting messages as "must be <desired type>, not <actual type>". */
static char * static char *
convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf) convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf)
{ {
char *msg = convertsimple1(arg, p_format, p_va); char *msg = convertsimple1(arg, p_format, p_va);
if (msg != NULL) { if (msg != NULL) {
sprintf(msgbuf, "%.50s, %.50s", msg, sprintf(msgbuf, "must be %.50s, not %.50s", msg,
arg == Py_None ? "None" : arg->ob_type->tp_name); arg == Py_None ? "None" : arg->ob_type->tp_name);
msg = msgbuf; msg = msgbuf;
} }
...@@ -1063,8 +1071,9 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format, ...@@ -1063,8 +1071,9 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
if (len < min || max < len) { if (len < min || max < len) {
if (message == NULL) { if (message == NULL) {
sprintf(msgbuf, sprintf(msgbuf,
"%s requires %s %d argument%s; %d given", "%s%s takes %s %d argument%s (%d given)",
fname==NULL ? "function" : fname, fname==NULL ? "function" : fname,
fname==NULL ? "" : "()",
min==max ? "exactly" min==max ? "exactly"
: len < min ? "at least" : "at most", : len < min ? "at least" : "at most",
len < min ? min : max, len < min ? min : max,
......
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