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__.
This commit is contained in:
Guido van Rossum 2001-10-22 00:43:43 +00:00
parent d6bebce5e5
commit c8e5645f15
5 changed files with 45 additions and 12 deletions

View File

@ -14,15 +14,22 @@ typedef struct PyGetSetDef {
typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
void *wrapped); void *wrapped);
typedef PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args,
void *wrapped, PyObject *kwds);
struct wrapperbase { struct wrapperbase {
char *name; char *name;
int offset; int offset;
void *function; void *function;
wrapperfunc wrapper; wrapperfunc wrapper;
char *doc; char *doc;
int flags;
PyObject *name_strobj; PyObject *name_strobj;
}; };
/* Flags for above struct */
#define PyWrapperFlag_KEYWORDS 1 /* wrapper function takes keyword args */
/* Various kinds of descriptor objects */ /* Various kinds of descriptor objects */
#define PyDescr_COMMON \ #define PyDescr_COMMON \

View File

@ -2340,6 +2340,14 @@ def str_of_str_subclass():
vereq(capture.getvalue(), '41\n41\n') vereq(capture.getvalue(), '41\n41\n')
capture.close() 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(): def test_main():
class_docstrings() class_docstrings()
lists() lists()
@ -2389,6 +2397,7 @@ def test_main():
subclasspropagation() subclasspropagation()
buffer_inherit() buffer_inherit()
str_of_str_subclass() str_of_str_subclass()
kwdargs()
if verbose: print "All OK" if verbose: print "All OK"
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -4,6 +4,10 @@ XXX Planned XXX Release date: 14-Nov-2001
Type/class unification and new-style classes 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 Core and builtins
Extension modules Extension modules

View File

@ -805,6 +805,17 @@ wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds)
wrapperfunc wrapper = wp->descr->d_base->wrapper; wrapperfunc wrapper = wp->descr->d_base->wrapper;
PyObject *self = wp->self; 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); return (*wrapper)(self, args, wp->descr->d_wrapped);
} }

View File

@ -2251,12 +2251,11 @@ wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped)
} }
static PyObject * static PyObject *
wrap_call(PyObject *self, PyObject *args, void *wrapped) wrap_call(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
{ {
ternaryfunc func = (ternaryfunc)wrapped; ternaryfunc func = (ternaryfunc)wrapped;
/* XXX What about keyword arguments? */ return (*func)(self, args, kwds);
return (*func)(self, args, NULL);
} }
static PyObject * static PyObject *
@ -2328,12 +2327,11 @@ wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
} }
static PyObject * static PyObject *
wrap_init(PyObject *self, PyObject *args, void *wrapped) wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds)
{ {
initproc func = (initproc)wrapped; initproc func = (initproc)wrapped;
/* XXX What about keyword arguments? */ if (func(self, args, kwds) < 0)
if (func(self, args, NULL) < 0)
return NULL; return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
@ -3177,6 +3175,7 @@ slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
typedef struct wrapperbase slotdef; typedef struct wrapperbase slotdef;
#undef TPSLOT #undef TPSLOT
#undef FLSLOT
#undef ETSLOT #undef ETSLOT
#undef SQSLOT #undef SQSLOT
#undef MPSLOT #undef MPSLOT
@ -3188,6 +3187,9 @@ typedef struct wrapperbase slotdef;
#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ #define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{NAME, offsetof(PyTypeObject, SLOT), (void *)(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) \ #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
{NAME, offsetof(etype, SLOT), (void *)(FUNCTION), WRAPPER, DOC} {NAME, offsetof(etype, SLOT), (void *)(FUNCTION), WRAPPER, DOC}
#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ #define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
@ -3346,8 +3348,8 @@ static slotdef slotdefs[] = {
"x.__cmp__(y) <==> cmp(x,y)"), "x.__cmp__(y) <==> cmp(x,y)"),
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
"x.__hash__() <==> hash(x)"), "x.__hash__() <==> hash(x)"),
TPSLOT("__call__", tp_call, slot_tp_call, wrap_call, FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
"x.__call__(...) <==> x(...)"), "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS),
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook,
wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"), wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"),
TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""), TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
@ -3379,11 +3381,11 @@ static slotdef slotdefs[] = {
"descr.__get__(obj[, type]) -> value"), "descr.__get__(obj[, type]) -> value"),
TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set, TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set,
"descr.__set__(obj, value)"), "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; " "x.__init__(...) initializes x; "
"see x.__class__.__doc__ for signature"), "see x.__class__.__doc__ for signature",
TPSLOT("__new__", tp_new, slot_tp_new, NULL, PyWrapperFlag_KEYWORDS),
""), TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""),
{NULL} {NULL}
}; };