bpo-30534: Fixed error messages when pass keyword arguments (#1901) · pythoncapi/cpython@5eb788b · GitHub
Skip to content

Commit 5eb788b

Browse files
bpo-30534: Fixed error messages when pass keyword arguments (python#1901)
to functions implemented in C that don't support this. Also unified error messages for functions that don't take positional or keyword arguments.
1 parent 5cefb6c commit 5eb788b

5 files changed

Lines changed: 116 additions & 45 deletions

File tree

Lib/test/test_call.py

Lines changed: 57 additions & 3 deletions

Lib/test/test_itertools.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1996,7 +1996,7 @@ def __init__(self, newarg=None, *args):
19961996
Subclass(newarg=1)
19971997
except TypeError as err:
19981998
# we expect type errors because of wrong argument count
1999-
self.assertNotIn("does not take keyword arguments", err.args[0])
1999+
self.assertNotIn("keyword arguments", err.args[0])
20002000

20012001
@support.cpython_only
20022002
class SizeofTest(unittest.TestCase):

Objects/call.c

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -466,38 +466,37 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg
466466
switch (flags)
467467
{
468468
case METH_NOARGS:
469+
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
470+
goto no_keyword_error;
471+
}
472+
469473
if (nargs != 0) {
470474
PyErr_Format(PyExc_TypeError,
471475
"%.200s() takes no arguments (%zd given)",
472476
method->ml_name, nargs);
473477
goto exit;
474478
}
475479

476-
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
477-
goto no_keyword_error;
478-
}
479-
480480
result = (*meth) (self, NULL);
481481
break;
482482

483483
case METH_O:
484+
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
485+
goto no_keyword_error;
486+
}
487+
484488
if (nargs != 1) {
485489
PyErr_Format(PyExc_TypeError,
486490
"%.200s() takes exactly one argument (%zd given)",
487491
method->ml_name, nargs);
488492
goto exit;
489493
}
490494

491-
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
492-
goto no_keyword_error;
493-
}
494-
495495
result = (*meth) (self, args[0]);
496496
break;
497497

498498
case METH_VARARGS:
499-
if (!(flags & METH_KEYWORDS)
500-
&& kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
499+
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
501500
goto no_keyword_error;
502501
}
503502
/* fall through next case */
@@ -592,7 +591,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject *
592591

593592
PyCFunction meth = method->ml_meth;
594593
int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
595-
Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames);
594+
Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_GET_SIZE(kwnames);
596595
PyObject *result = NULL;
597596

598597
if (Py_EnterRecursiveCall(" while calling a Python object")) {
@@ -602,32 +601,32 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject *
602601
switch (flags)
603602
{
604603
case METH_NOARGS:
604+
if (nkwargs) {
605+
goto no_keyword_error;
606+
}
607+
605608
if (nargs != 0) {
606609
PyErr_Format(PyExc_TypeError,
607610
"%.200s() takes no arguments (%zd given)",
608611
method->ml_name, nargs);
609612
goto exit;
610613
}
611614

612-
if (nkwargs) {
613-
goto no_keyword_error;
614-
}
615-
616615
result = (*meth) (self, NULL);
617616
break;
618617

619618
case METH_O:
619+
if (nkwargs) {
620+
goto no_keyword_error;
621+
}
622+
620623
if (nargs != 1) {
621624
PyErr_Format(PyExc_TypeError,
622625
"%.200s() takes exactly one argument (%zd given)",
623626
method->ml_name, nargs);
624627
goto exit;
625628
}
626629

627-
if (nkwargs) {
628-
goto no_keyword_error;
629-
}
630-
631630
result = (*meth) (self, args[0]);
632631
break;
633632

@@ -637,16 +636,17 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject *
637636
break;
638637

639638
case METH_VARARGS:
639+
if (nkwargs) {
640+
goto no_keyword_error;
641+
}
642+
/* fall through next case */
643+
640644
case METH_VARARGS | METH_KEYWORDS:
641645
{
642646
/* Slow-path: create a temporary tuple for positional arguments
643647
and a temporary dict for keyword arguments */
644648
PyObject *argtuple;
645649

646-
if (!(flags & METH_KEYWORDS) && nkwargs) {
647-
goto no_keyword_error;
648-
}
649-
650650
argtuple = _PyStack_AsTuple(args, nargs);
651651
if (argtuple == NULL) {
652652
goto exit;
@@ -717,6 +717,7 @@ static PyObject *
717717
cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs)
718718
{
719719
assert(!PyErr_Occurred());
720+
assert(kwargs == NULL || PyDict_Check(kwargs));
720721

721722
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
722723
PyObject *self = PyCFunction_GET_SELF(func);
@@ -732,7 +733,7 @@ cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs)
732733
Py_LeaveRecursiveCall();
733734
}
734735
else {
735-
if (kwargs != NULL && PyDict_Size(kwargs) != 0) {
736+
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
736737
PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
737738
((PyCFunctionObject*)func)->m_ml->ml_name);
738739
return NULL;

Objects/descrobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,7 @@ wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
11761176

11771177
if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_GET_SIZE(kwds) != 0)) {
11781178
PyErr_Format(PyExc_TypeError,
1179-
"wrapper %s doesn't take keyword arguments",
1179+
"wrapper %s() takes no keyword arguments",
11801180
wp->descr->d_base->name);
11811181
return NULL;
11821182
}

Python/getargs.c

Lines changed: 32 additions & 16 deletions

0 commit comments

Comments
 (0)