]> granicus.if.org Git - python/commitdiff
Methods of built-in types now properly check for keyword arguments
authorGuido van Rossum <guido@python.org>
Mon, 22 Oct 2001 00:43:43 +0000 (00:43 +0000)
committerGuido van Rossum <guido@python.org>
Mon, 22 Oct 2001 00:43:43 +0000 (00:43 +0000)
(formerly these were silently ignored).  The only built-in methods
that take keyword arguments are __call__, __init__ and __new__.

Include/descrobject.h
Lib/test/test_descr.py
Misc/NEWS
Objects/descrobject.c
Objects/typeobject.c

index 9a071101531bb78deba0f0e713442e1d0465c2ce..918dd5a0420de413978319c047af1788edceedf6 100644 (file)
@@ -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 \
index 962c1cc7a040f358b0d8e56e9a4af7311e304d99..d7a06447e5efb131a416cbf9798aa61cd75fbe2b 100644 (file)
@@ -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__":
index a039a7195cb920aa56f78bddc5e3187ed2775e7e..83c978c51e31996a2f701b0f2c2d853c343864d6 100644 (file)
--- 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
index e4d9f33023fdf77fe633ebda44b5e9fa7784fc66..c5e793d874e342a2bfd44d03d2e4fe00b74fa093 100644 (file)
@@ -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);
 }
 
index 4e8f9676d391b58756eba1f51cd47d4d62a0e3bf..5952b4efcff2b4d79d75dfb7a20fdfc1b5d44e0f 100644 (file)
@@ -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}
 };