summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFred Drake <fdrake@acm.org>2001-01-04 22:33:02 (GMT)
committerFred Drake <fdrake@acm.org>2001-01-04 22:33:02 (GMT)
commit1a7aab70d1f56b63ba6798db1cafe0a61cc3da15 (patch)
tree2866a950471b75591faadbbf350185be902b9f2b
parentbe4c0f56a28831f6121ef545ca8afb44a6723022 (diff)
downloadcpython-1a7aab70d1f56b63ba6798db1cafe0a61cc3da15.zip
cpython-1a7aab70d1f56b63ba6798db1cafe0a61cc3da15.tar.gz
cpython-1a7aab70d1f56b63ba6798db1cafe0a61cc3da15.tar.bz2
When a PyCFunction that takes only positional parameters is called with
an empty keywords dictionary (via apply() or the extended call syntax), the keywords dict should be ignored. If the keywords dict is not empty, TypeError should be raised. (Between the restructuring of the call machinery and this patch, an empty dict in this situation would trigger a SystemError via PyErr_BadInternalCall().) Added regression tests to detect errors for this.
-rw-r--r--Lib/test/test_b1.py11
-rw-r--r--Lib/test/test_extcall.py12
-rw-r--r--Python/ceval.c37
3 files changed, 41 insertions, 19 deletions
diff --git a/Lib/test/test_b1.py b/Lib/test/test_b1.py
index 6d6aa6f..9511079 100644
--- a/Lib/test/test_b1.py
+++ b/Lib/test/test_b1.py
@@ -39,6 +39,17 @@ apply(f1, (1,))
apply(f2, (1, 2))
apply(f3, (1, 2, 3))
+# A PyCFunction that takes only positional parameters should allow an
+# empty keyword dictionary to pass without a complaint, but raise a
+# TypeError if the dictionary is non-empty.
+apply(id, (1,), {})
+try:
+ apply(id, (1,), {"foo": 1})
+except TypeError:
+ pass
+else:
+ raise TestFailed, 'expected TypeError; no exception raised'
+
print 'callable'
if not callable(len):raise TestFailed, 'callable(len)'
def f(): pass
diff --git a/Lib/test/test_extcall.py b/Lib/test/test_extcall.py
index 7dddabc..cc42818 100644
--- a/Lib/test/test_extcall.py
+++ b/Lib/test/test_extcall.py
@@ -1,4 +1,5 @@
from UserList import UserList
+from test_support import TestFailed
def f(*a, **k):
print a, k
@@ -161,4 +162,13 @@ try:
except TypeError, err:
print err
-
+# A PyCFunction that takes only positional parameters should allow an
+# empty keyword dictionary to pass without a complaint, but raise a
+# TypeError if the dictionary is non-empty.
+id(1, **{})
+try:
+ id(1, **{"foo": 1})
+except TypeError:
+ pass
+else:
+ raise TestFailed, 'expected TypeError; no exception raised'
diff --git a/Python/ceval.c b/Python/ceval.c
index dd626e5..1559456 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2607,23 +2607,30 @@ call_cfunction(PyObject *func, PyObject *arg, PyObject *kw)
PyObject *self = PyCFunction_GET_SELF(func);
int flags = PyCFunction_GET_FLAGS(func);
- if (flags & METH_KEYWORDS && kw == NULL) {
- static PyObject *dict = NULL;
- if (dict == NULL) {
- dict = PyDict_New();
- if (dict == NULL)
- return NULL;
+ if (flags & METH_KEYWORDS) {
+ if (kw == NULL) {
+ static PyObject *dict = NULL;
+ if (dict == NULL) {
+ dict = PyDict_New();
+ if (dict == NULL)
+ return NULL;
+ }
+ kw = dict;
+ Py_INCREF(dict);
}
- kw = dict;
- Py_INCREF(dict);
+ return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
}
- if (flags & METH_VARARGS && kw == NULL) {
- return (*meth)(self, arg);
+ if (kw != NULL && PyDict_Size(kw) != 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() takes no keyword arguments",
+ f->m_ml->ml_name);
+ return NULL;
}
- if (flags & METH_KEYWORDS) {
- return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
+ if (flags & METH_VARARGS) {
+ return (*meth)(self, arg);
}
if (!(flags & METH_VARARGS)) {
+ /* the really old style */
int size = PyTuple_GET_SIZE(arg);
if (size == 1)
arg = PyTuple_GET_ITEM(arg, 0);
@@ -2631,12 +2638,6 @@ call_cfunction(PyObject *func, PyObject *arg, PyObject *kw)
arg = NULL;
return (*meth)(self, arg);
}
- if (kw != NULL && PyDict_Size(kw) != 0) {
- PyErr_Format(PyExc_TypeError,
- "%.200s() takes no keyword arguments",
- f->m_ml->ml_name);
- return NULL;
- }
/* should never get here ??? */
PyErr_BadInternalCall();
return NULL;