diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py index f1fff0a5eca..a5af50b7206 100644 --- a/Lib/test/test_extcall.py +++ b/Lib/test/test_extcall.py @@ -1,3 +1,4 @@ + """Doctest for method/function calls. We're going the use these types for extra testing @@ -65,17 +66,17 @@ >>> g() Traceback (most recent call last): ... - TypeError: g() takes at least 1 positional argument (0 given) + TypeError: g() takes at least 1 argument (0 given) >>> g(*()) Traceback (most recent call last): ... - TypeError: g() takes at least 1 positional argument (0 given) + TypeError: g() takes at least 1 argument (0 given) >>> g(*(), **{}) Traceback (most recent call last): ... - TypeError: g() takes at least 1 positional argument (0 given) + TypeError: g() takes at least 1 argument (0 given) >>> g(1) 1 () {} @@ -261,13 +262,31 @@ ... print(a,b) >>> f(**x) 1 2 + +A obscure message: + + >>> def f(a, b): + ... pass + >>> f(b=1) + Traceback (most recent call last): + ... + TypeError: f() takes exactly 2 arguments (1 given) + +The number of arguments passed in includes keywords: + + >>> def f(a): + ... pass + >>> f(6, a=4, *(1, 2, 3)) + Traceback (most recent call last): + ... + TypeError: f() takes exactly 1 argument (5 given) """ +import sys from test import support def test_main(): - from test import test_extcall # self import - support.run_doctest(test_extcall, True) + support.run_doctest(sys.modules[__name__], True) if __name__ == '__main__': test_main() diff --git a/Python/ceval.c b/Python/ceval.c index 4e9f77be8ac..ae9ab477909 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3076,13 +3076,12 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, if (!(co->co_flags & CO_VARARGS)) { PyErr_Format(PyExc_TypeError, "%U() takes %s %d " - "%spositional argument%s (%d given)", + "argument%s (%d given)", co->co_name, defcount ? "at most" : "exactly", co->co_argcount, - kwcount ? "non-keyword " : "", co->co_argcount == 1 ? "" : "s", - argcount); + argcount + kwcount); goto fail; } n = co->co_argcount; @@ -3116,7 +3115,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, } /* Speed hack: do raw pointer compares. As names are normally interned this should almost always hit. */ - co_varnames = PySequence_Fast_ITEMS(co->co_varnames); + co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item; for (j = 0; j < co->co_argcount + co->co_kwonlyargcount; j++) { @@ -3148,10 +3147,10 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, keyword); goto fail; } - PyDict_SetItem(kwdict, keyword, value); - continue; } -kw_found: + PyDict_SetItem(kwdict, keyword, value); + continue; + kw_found: if (GETLOCAL(j) != NULL) { PyErr_Format(PyExc_TypeError, "%U() got multiple " @@ -3190,16 +3189,19 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, int m = co->co_argcount - defcount; for (i = argcount; i < m; i++) { if (GETLOCAL(i) == NULL) { + int j, given = 0; + for (j = 0; j < co->co_argcount; j++) + if (GETLOCAL(j)) + given++; PyErr_Format(PyExc_TypeError, "%U() takes %s %d " - "%spositional argument%s " + "argument%s " "(%d given)", co->co_name, ((co->co_flags & CO_VARARGS) || defcount) ? "at least" : "exactly", - m, kwcount ? "non-keyword " : "", - m == 1 ? "" : "s", i); + m, m == 1 ? "" : "s", given); goto fail; } } @@ -3216,14 +3218,12 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, } } } - else { - if (argcount > 0 || kwcount > 0) { - PyErr_Format(PyExc_TypeError, - "%U() takes no arguments (%d given)", - co->co_name, - argcount + kwcount); - goto fail; - } + else if (argcount > 0 || kwcount > 0) { + PyErr_Format(PyExc_TypeError, + "%U() takes no arguments (%d given)", + co->co_name, + argcount + kwcount); + goto fail; } /* Allocate and initialize storage for cell vars, and copy free vars into frame. This isn't too efficient right now. */