summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2001-10-22 00:43:43 (GMT)
committerGuido van Rossum <guido@python.org>2001-10-22 00:43:43 (GMT)
commitc8e5645f15054a87945d5f62dc23c6e49a394db5 (patch)
tree94172c8b5b197c564ba64789b81cd41334b996a9
parentd6bebce5e5a6e92b6949dd001d3d467a7aa1aaef (diff)
downloadcpython-c8e5645f15054a87945d5f62dc23c6e49a394db5.zip
cpython-c8e5645f15054a87945d5f62dc23c6e49a394db5.tar.gz
cpython-c8e5645f15054a87945d5f62dc23c6e49a394db5.tar.bz2
Methods of built-in types now properly check for keyword arguments
(formerly these were silently ignored). The only built-in methods that take keyword arguments are __call__, __init__ and __new__.
-rw-r--r--Include/descrobject.h7
-rw-r--r--Lib/test/test_descr.py9
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/descrobject.c11
-rw-r--r--Objects/typeobject.c26
5 files changed, 45 insertions, 12 deletions
diff --git a/Include/descrobject.h b/Include/descrobject.h
index 9a07110..918dd5a 100644
--- a/Include/descrobject.h
+++ b/Include/descrobject.h
@@ -14,15 +14,22 @@ typedef struct PyGetSetDef {
typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
void *wrapped);
+typedef PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args,
+ void *wrapped, PyObject *kwds);
+
struct wrapperbase {
char *name;
int offset;
void *function;
wrapperfunc wrapper;
char *doc;
+ int flags;
PyObject *name_strobj;
};
+/* Flags for above struct */
+#define PyWrapperFlag_KEYWORDS 1 /* wrapper function takes keyword args */
+
/* Various kinds of descriptor objects */
#define PyDescr_COMMON \
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 962c1cc..d7a0644 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -2340,6 +2340,14 @@ def str_of_str_subclass():
vereq(capture.getvalue(), '41\n41\n')
capture.close()
+def kwdargs():
+ if verbose: print "Testing keyword arguments to __init__, __call__..."
+ def f(a): return a
+ vereq(f.__call__(a=42), 42)
+ a = []
+ list.__init__(a, sequence=[0, 1, 2])
+ vereq(a, [0, 1, 2])
+
def test_main():
class_docstrings()
lists()
@@ -2389,6 +2397,7 @@ def test_main():
subclasspropagation()
buffer_inherit()
str_of_str_subclass()
+ kwdargs()
if verbose: print "All OK"
if __name__ == "__main__":
diff --git a/Misc/NEWS b/Misc/NEWS
index a039a71..83c978c 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -4,6 +4,10 @@ XXX Planned XXX Release date: 14-Nov-2001
Type/class unification and new-style classes
+- Methods of built-in types now properly check for keyword arguments
+ (formerly these were silently ignored). The only built-in methods
+ that take keyword arguments are __call__, __init__ and __new__.
+
Core and builtins
Extension modules
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index e4d9f33..c5e793d 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -805,6 +805,17 @@ wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
wrapperfunc wrapper = wp->descr->d_base->wrapper;
PyObject *self = wp->self;
+ if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
+ wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper;
+ return (*wk)(self, args, wp->descr->d_wrapped, kwds);
+ }
+
+ if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) {
+ PyErr_Format(PyExc_TypeError,
+ "wrapper %s doesn't take keyword arguments",
+ wp->descr->d_base->name);
+ return NULL;
+ }
return (*wrapper)(self, args, wp->descr->d_wrapped);
}
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 4e8f967..5952b4e 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -2251,12 +2251,11 @@ wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped)
}
static PyObject *
-wrap_call(PyObject *self, PyObject *args, void *wrapped)
+wrap_call(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
{
ternaryfunc func = (ternaryfunc)wrapped;
- /* XXX What about keyword arguments? */
- return (*func)(self, args, NULL);
+ return (*func)(self, args, kwds);
}
static PyObject *
@@ -2328,12 +2327,11 @@ wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
}
static PyObject *
-wrap_init(PyObject *self, PyObject *args, void *wrapped)
+wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
{
initproc func = (initproc)wrapped;
- /* XXX What about keyword arguments? */
- if (func(self, args, NULL) < 0)
+ if (func(self, args, kwds) < 0)
return NULL;
Py_INCREF(Py_None);
return Py_None;
@@ -3177,6 +3175,7 @@ slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
typedef struct wrapperbase slotdef;
#undef TPSLOT
+#undef FLSLOT
#undef ETSLOT
#undef SQSLOT
#undef MPSLOT
@@ -3188,6 +3187,9 @@ typedef struct wrapperbase slotdef;
#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, DOC}
+#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \
+ {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
+ DOC, FLAGS}
#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{NAME, offsetof(etype, SLOT), (void *)(FUNCTION), WRAPPER, DOC}
#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
@@ -3346,8 +3348,8 @@ static slotdef slotdefs[] = {
"x.__cmp__(y) <==> cmp(x,y)"),
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
"x.__hash__() <==> hash(x)"),
- TPSLOT("__call__", tp_call, slot_tp_call, wrap_call,
- "x.__call__(...) <==> x(...)"),
+ FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
+ "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS),
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
@@ -3379,11 +3381,11 @@ static slotdef slotdefs[] = {
"descr.__get__(obj[, type]) -> value"),
TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set,
"descr.__set__(obj, value)"),
- TPSLOT("__init__", tp_init, slot_tp_init, wrap_init,
+ FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init,
"x.__init__(...) initializes x; "
- "see x.__class__.__doc__ for signature"),
- TPSLOT("__new__", tp_new, slot_tp_new, NULL,
- ""),
+ "see x.__class__.__doc__ for signature",
+ PyWrapperFlag_KEYWORDS),
+ TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
{NULL}
};