mirror of https://github.com/python/cpython
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:
parent
d6bebce5e5
commit
c8e5645f15
|
@ -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 \
|
||||||
|
|
|
@ -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__":
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue