]> granicus.if.org Git - python/commitdiff
This patch makes sure that the function name always appears in the error
authorKa-Ping Yee <ping@zesty.ca>
Mon, 15 Jan 2001 22:14:16 +0000 (22:14 +0000)
committerKa-Ping Yee <ping@zesty.ca>
Mon, 15 Jan 2001 22:14:16 +0000 (22:14 +0000)
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.

Lib/test/output/test_extcall
Lib/test/output/test_pyexpat
Lib/test/test_extcall.py
Python/ceval.c
Python/getargs.c

index 87102af2032720ec978cefdc56e29eaca2067937..d289f5493f0e5fea8a612f5d9ca62fc665415311 100644 (file)
@@ -9,9 +9,9 @@ test_extcall
 (1, 2, 3) {'b': 5, 'a': 4}
 (1, 2, 3, 4, 5) {'b': 7, 'a': 6}
 (1, 2, 3, 6, 7) {'y': 5, 'b': 9, 'x': 4, 'a': 8}
-TypeError: not enough arguments to g(); expected 1, got 0
-TypeError: not enough arguments to g(); expected 1, got 0
-TypeError: not enough arguments to g(); expected 1, got 0
+TypeError: g() takes at least 1 argument (0 given)
+TypeError: g() takes at least 1 argument (0 given)
+TypeError: g() takes at least 1 argument (0 given)
 1 () {}
 1 (2,) {}
 1 (2, 3) {}
@@ -20,14 +20,89 @@ TypeError: not enough arguments to g(); expected 1, got 0
 1 () {'d': 4, '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()
-keyword parameter 'b' redefined in function call
-keywords must be strings
+g() got multiple values for keyword argument 'x'
+g() got multiple values for keyword argument 'b'
+f() keywords must be strings
 h() got an unexpected keyword argument 'e'
-* argument must be a sequence
-** argument must be a dictionary
+h() argument after * must be a sequence
+h() argument after ** must be a dictionary
 3 512 1
 3
 3
-unbound 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
+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'
index 4d9981cbbeb00ac8132c31b43dee238e0d18b13e..5d6160a9c2107b65edfa5b8a6522722ab149ab1c 100644 (file)
@@ -97,7 +97,7 @@ End element:
 Testing constructor for proper handling of namespace_separator values:
 Legal values tested o.k.
 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:
 namespace_separator must be one character, omitted, or None
 Caught expected ValueError:
index cc42818c9a6ba61185471deb4b17d485a60a4b31..b53ced75038dd14b09a51554d1230f67ac40514a 100644 (file)
@@ -1,5 +1,6 @@
 from UserList import UserList
 from test_support import TestFailed
+import string
 
 def f(*a, **k):
     print a, k
@@ -172,3 +173,32 @@ except TypeError:
     pass
 else:
     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
index ed201b390fcd6b0a5bcdbcc35337faafbedd32e8..36f0017c3a13a93a8baaed2da6429ac80c725ecf 100644 (file)
@@ -48,8 +48,8 @@ static PyObject *fast_function(PyObject *, PyObject ***, int, int, int);
 static PyObject *fast_cfunction(PyObject *, PyObject ***, int);
 static PyObject *do_call(PyObject *, PyObject ***, int, int);
 static PyObject *ext_do_call(PyObject *, PyObject ***, int, int, int);
-static PyObject *update_keyword_args(PyObject *, int, PyObject ***);
-static PyObject *update_star_args(int, int, PyObject *,        PyObject ***);
+static PyObject *update_keyword_args(PyObject *, int, PyObject ***, PyObject *);
+static PyObject *update_star_args(int, int, PyObject *, PyObject ***);
 static PyObject *load_args(PyObject ***, int);
 #define CALL_FLAG_VAR 1
 #define CALL_FLAG_KW 2
@@ -451,10 +451,14 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
                if (argcount > co->co_argcount) {
                        if (!(co->co_flags & CO_VARARGS)) {
                                PyErr_Format(PyExc_TypeError,
-                                   "too many arguments to %s(); "
-                                   "expected %d, got %d",
+                                   "%.200s() takes %s %d "
+                                   "%sargument%s (%d given)",
                                    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;
                        }
                        n = co->co_argcount;
@@ -480,8 +484,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
                        PyObject *value = kws[2*i + 1];
                        int j;
                        if (keyword == NULL || !PyString_Check(keyword)) {
-                               PyErr_SetString(PyExc_TypeError,
-                                               "keywords must be strings");
+                               PyErr_Format(PyExc_TypeError,
+                                   "%.200s() keywords must be strings",
+                                   PyString_AsString(co->co_name));
                                goto fail;
                        }
                        /* XXX slow -- speed up using dictionary? */
@@ -508,10 +513,11 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
                        else {
                                if (GETLOCAL(j) != NULL) {
                                        PyErr_Format(PyExc_TypeError, 
-                                            "keyword parameter '%.400s' "
-                                            "redefined in call to %.200s()",
-                                            PyString_AsString(keyword),
-                                            PyString_AsString(co->co_name));
+                                            "%.200s() got multiple "
+                                            "values for keyword "
+                                            "argument '%.400s'",
+                                            PyString_AsString(co->co_name),
+                                            PyString_AsString(keyword));
                                        goto fail;
                                }
                                Py_INCREF(value);
@@ -523,10 +529,14 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
                        for (i = argcount; i < m; i++) {
                                if (GETLOCAL(i) == NULL) {
                                        PyErr_Format(PyExc_TypeError,
-                                           "not enough arguments to "
-                                           "%.200s(); expected %d, got %d",
+                                           "%.200s() takes %s %d "
+                                           "%sargument%s (%d given)",
                                            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;
                                }
                        }
@@ -546,8 +556,9 @@ eval_code2(PyCodeObject *co, PyObject *globals, PyObject *locals,
        else {
                if (argcount > 0 || kwcount > 0) {
                        PyErr_Format(PyExc_TypeError,
-                                    "%.200s() expected no arguments",
-                                    PyString_AsString(co->co_name));
+                                    "%.200s() takes no arguments (%d given)",
+                                    PyString_AsString(co->co_name),
+                                    argcount + kwcount);
                        goto fail;
                }
        }
@@ -2669,8 +2680,12 @@ call_method(PyObject *func, PyObject *arg, PyObject *kw)
                    && PyClass_IsSubclass((PyObject *)
                                  (((PyInstanceObject *)self)->in_class),
                                          class))) {
-               PyErr_SetString(PyExc_TypeError,
-       "unbound method must be called with instance as first argument");
+                PyObject* fn = ((PyFunctionObject*) func)->func_name;
+               PyErr_Format(PyExc_TypeError,
+                             "unbound method %s%smust be "
+                             "called with instance as first argument",
+                             fn ? PyString_AsString(fn) : "",
+                             fn ? "() " : "");
                        return NULL;
                }
                Py_INCREF(arg);
@@ -2793,7 +2808,8 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
 }
 
 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;
        if (orig_kwdict == NULL)
@@ -2809,10 +2825,12 @@ update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack)
                PyObject *value = EXT_POP(*pp_stack);
                PyObject *key = EXT_POP(*pp_stack);
                if (PyDict_GetItem(kwdict, key) != NULL) {
-                       PyErr_Format(PyExc_TypeError, 
-                                    "keyword parameter '%.400s' "
-                                    "redefined in function call",
-                                    PyString_AsString(key));
+                        PyObject* fn = ((PyFunctionObject*) func)->func_name;
+                        PyErr_Format(PyExc_TypeError, 
+                                     "%.200s%s got multiple values "
+                                     "for keyword argument '%.400s'",
+                                     fn ? PyString_AsString(fn) : "function",
+                                     fn ? "()" : "", PyString_AsString(key));
                        Py_DECREF(key);
                        Py_DECREF(value);
                        Py_DECREF(kwdict);
@@ -2877,7 +2895,7 @@ do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
        PyObject *result = NULL;
 
        if (nk > 0) {
-               kwdict = update_keyword_args(NULL, nk, pp_stack);
+               kwdict = update_keyword_args(NULL, nk, pp_stack, func);
                if (kwdict == NULL)
                        goto call_fail;
        }
@@ -2903,8 +2921,11 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
        if (flags & CALL_FLAG_KW) {
                kwdict = EXT_POP(*pp_stack);
                if (!(kwdict && PyDict_Check(kwdict))) {
-                       PyErr_SetString(PyExc_TypeError,
-                                       "** argument must be a dictionary");
+                        PyObject* fn = ((PyFunctionObject*) func)->func_name;
+                       PyErr_Format(PyExc_TypeError,
+                            "%s%s argument after ** must be a dictionary",
+                            fn ? PyString_AsString(fn) : "function",
+                            fn ? "()" : "");
                        goto ext_call_fail;
                }
        }
@@ -2915,8 +2936,12 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
                        t = PySequence_Tuple(stararg);
                        if (t == NULL) {
                            if (PyErr_ExceptionMatches(PyExc_TypeError)) {
-                               PyErr_SetString(PyExc_TypeError,
-                                       "* argument must be a sequence");
+                                PyObject* fn =
+                                    ((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;
                        }
@@ -2926,7 +2951,7 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
                nstar = PyTuple_GET_SIZE(stararg);
        }
        if (nk > 0) {
-               kwdict = update_keyword_args(kwdict, nk, pp_stack);
+               kwdict = update_keyword_args(kwdict, nk, pp_stack, func);
                if (kwdict == NULL)
                        goto ext_call_fail;
        }
index cf1c6b72a2707f61447e05d9cb4ae61df03db092..5a9418380b6dd33c225422c066da4f034259af51 100644 (file)
@@ -130,16 +130,18 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
                if (max == 0) {
                        if (args == NULL)
                                return 1;
-                       sprintf(msgbuf, "%s requires no arguments",
-                               fname==NULL ? "function" : fname);
+                       sprintf(msgbuf, "%s%s takes no arguments",
+                               fname==NULL ? "function" : fname,
+                               fname==NULL ? "" : "()");
                        PyErr_SetString(PyExc_TypeError, msgbuf);
                        return 0;
                }
                else if (min == 1 && max == 1) {
                        if (args == NULL) {
                                sprintf(msgbuf,
-                                       "%s requires at least one argument",
-                                       fname==NULL ? "function" : fname);
+                                       "%s%s takes at least one argument",
+                                       fname==NULL ? "function" : fname,
+                                       fname==NULL ? "" : "()");
                                PyErr_SetString(PyExc_TypeError, msgbuf);
                                return 0;
                        }
@@ -167,8 +169,9 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
        if (len < min || max < len) {
                if (message == NULL) {
                        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 ? "" : "()",
                                min==max ? "exactly"
                                         : len < min ? "at least" : "at most",
                                len < min ? min : max,
@@ -213,22 +216,26 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message)
 
        if (PyErr_Occurred())
                return;
-       if (iarg == 0 && message == NULL)
-               message = msg;
        else if (message == NULL) {
                if (fname != NULL) {
-                       sprintf(p, "%s, ", fname);
+                       sprintf(p, "%s() ", fname);
                        p += strlen(p);
                }
-               sprintf(p, "argument %d", iarg);
-               i = 0;
-               p += strlen(p);
-               while (levels[i] > 0) {
-                       sprintf(p, ", item %d", levels[i]-1);
+               if (iarg != 0) {
+                       sprintf(p, "argument %d", iarg);
+                       i = 0;
+                       p += strlen(p);
+                       while (levels[i] > 0) {
+                               sprintf(p, ", item %d", levels[i]-1);
+                               p += strlen(p);
+                               i++;
+                       }
+               }
+               else {
+                       sprintf(p, "argument");
                        p += strlen(p);
-                       i++;
                }
-               sprintf(p, ": expected %s found", msg);
+               sprintf(p, " %s", msg);
                message = buf;
        }
        PyErr_SetString(PyExc_TypeError, message);
@@ -247,10 +254,9 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message)
       *p_va is undefined,
       *levels is a 0-terminated list of item numbers,
       *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
             <typename2> is the name of the actual type,
-         (so you can surround it by "expected ... found"),
       and msgbuf is returned.
 */
 
@@ -281,10 +287,11 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
                        n++;
        }
        
-       if (!PySequence_Check(arg)) {
+       if (!PySequence_Check(arg) || PyString_Check(arg)) {
                levels[0] = 0;
                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);
                return msgbuf;
        }
@@ -292,11 +299,12 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
        if ((i = PySequence_Size(arg)) != n) {
                levels[0] = 0;
                sprintf(msgbuf,
-                   toplevel ? "%d arguments, %d" : "%d-sequence, %d-sequence",
-                   n, i);
+                       toplevel ? "expected %d arguments, not %d" :
+                                  "must be sequence of length %d, not %d",
+                       n, i);
                return msgbuf;
        }
-       
+
        format = *p_format;
        for (i = 0; i < n; i++) {
                char *msg;
@@ -310,7 +318,7 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
                        return msg;
                }
        }
-       
+
        *p_format = format;
        return NULL;
 }
@@ -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
-   by appending ", <actual argument type>" to error message. */
+   by formatting messages as "must be <desired type>, not <actual type>". */
 
 static char *
 convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf)
 {
        char *msg = convertsimple1(arg, p_format, p_va);
        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);
                msg = msgbuf;
        }
@@ -1063,8 +1071,9 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
        if (len < min || max < len) {
                if (message == NULL) {
                        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 ? "" : "()",
                                min==max ? "exactly"
                                         : len < min ? "at least" : "at most",
                                len < min ? min : max,