diff -r bf5a899a5d7c Lib/test/test_extcall.py --- a/Lib/test/test_extcall.py Sun Apr 12 17:56:34 2015 -0400 +++ b/Lib/test/test_extcall.py Mon Apr 13 12:47:23 2015 -0400 @@ -284,17 +284,17 @@ >>> f(1, kw=3) Traceback (most recent call last): ... - TypeError: f() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given + TypeError: f() takes 0 positional arguments and 1 keyword-only argument but 1 positional argument (and 1 keyword-only argument) were given >>> def f(*, kw, b): pass >>> f(1, 2, 3, b=3, kw=3) Traceback (most recent call last): ... - TypeError: f() takes 0 positional arguments but 3 positional arguments (and 2 keyword-only arguments) were given + TypeError: f() takes 0 positional arguments and 2 keyword-only arguments but 3 positional arguments (and 2 keyword-only arguments) were given >>> def f(a, b=2, *, kw): pass >>> f(2, 3, 4, kw=4) Traceback (most recent call last): ... - TypeError: f() takes from 1 to 2 positional arguments but 3 positional arguments (and 1 keyword-only argument) were given + TypeError: f() takes from 1 to 2 positional arguments and 1 keyword-only argument but 3 positional arguments (and 1 keyword-only argument) were given Too few and missing arguments: diff -r bf5a899a5d7c Lib/test/test_keywordonlyarg.py --- a/Lib/test/test_keywordonlyarg.py Sun Apr 12 17:56:34 2015 -0400 +++ b/Lib/test/test_keywordonlyarg.py Mon Apr 13 12:47:23 2015 -0400 @@ -76,7 +76,17 @@ pass with self.assertRaises(TypeError) as exc: f(1, 2, 3) - expected = "f() takes from 1 to 2 positional arguments but 3 were given" + expected = ("f() takes from 1 to 2 positional arguments" + " and 1 keyword-only argument but 3 were given") + self.assertEqual(str(exc.exception), expected) + + def testTooManyPositionalErrorMessage2(self): + def f(a, b=None, *, c=None, d=None): + pass + with self.assertRaises(TypeError) as exc: + f(1, 2, 3) + expected = ("f() takes from 1 to 2 positional arguments" + " and 2 keyword-only arguments but 3 were given") self.assertEqual(str(exc.exception), expected) def testSyntaxErrorForFunctionCall(self): diff -r bf5a899a5d7c Python/ceval.c --- a/Python/ceval.c Sun Apr 12 17:56:34 2015 -0400 +++ b/Python/ceval.c Mon Apr 13 12:47:23 2015 -0400 @@ -3362,7 +3362,9 @@ int plural; int kwonly_given = 0; int i; - PyObject *sig, *kwonly_sig; + PyObject *sig, /* Show number of co's positional args */ + *kwonly_sig, /* Show number of co's keyword-only args */ + *kw_given_sig; /* Show number of keyword args given */ assert((co->co_flags & CO_VARARGS) == 0); /* Count missing keyword-only args. */ @@ -3380,30 +3382,46 @@ } if (sig == NULL) return; + if (co->co_kwonlyargcount) { + kwonly_sig = PyUnicode_FromFormat(" and %d keyword-only argument%s", + co->co_kwonlyargcount, + co->co_kwonlyargcount > 1 ? "s" : ""); + if (kwonly_sig == NULL) { + Py_DECREF(sig); + return; + } + } + else { + kwonly_sig = PyUnicode_FromString(""); + assert(kwonly_sig != NULL); + } if (kwonly_given) { const char *format = " positional argument%s (and %d keyword-only argument%s)"; - kwonly_sig = PyUnicode_FromFormat(format, given != 1 ? "s" : "", kwonly_given, - kwonly_given != 1 ? "s" : ""); - if (kwonly_sig == NULL) { + kw_given_sig = PyUnicode_FromFormat(format, given != 1 ? "s" : "", kwonly_given, + kwonly_given != 1 ? "s" : ""); + if (kw_given_sig == NULL) { Py_DECREF(sig); + Py_DECREF(kwonly_sig); return; } } else { /* This will not fail. */ - kwonly_sig = PyUnicode_FromString(""); - assert(kwonly_sig != NULL); + kw_given_sig = PyUnicode_FromString(""); + assert(kw_given_sig != NULL); } PyErr_Format(PyExc_TypeError, - "%U() takes %U positional argument%s but %d%U %s given", + "%U() takes %U positional argument%s%U but %d%U %s given", co->co_name, sig, plural ? "s" : "", + kwonly_sig, given, - kwonly_sig, + kw_given_sig, given == 1 && !kwonly_given ? "was" : "were"); Py_DECREF(sig); Py_DECREF(kwonly_sig); + Py_DECREF(kw_given_sig); } /* This is gonna seem *real weird*, but if you put some other code between