Put proper tests in classmethod_get(). Remove the type argument to
descr_check(); it wasn't useful. Change the type argument of the various _get() methods to PyObject * because the call signature of tp_descr_get doesn't guarantee its type.
This commit is contained in:
parent
6bae46d8c1
commit
b6e5a0c658
|
@ -3733,6 +3733,45 @@ def dict_type_with_metaclass():
|
|||
__metaclass__ = M
|
||||
veris(type(C.__dict__), type(B.__dict__))
|
||||
|
||||
def meth_class_get():
|
||||
# Full coverage of descrobject.c::classmethod_get()
|
||||
if verbose: print "Testing __get__ method of METH_CLASS C methods..."
|
||||
# Baseline
|
||||
arg = [1, 2, 3]
|
||||
res = {1: None, 2: None, 3: None}
|
||||
vereq(dict.fromkeys(arg), res)
|
||||
vereq({}.fromkeys(arg), res)
|
||||
# Now get the descriptor
|
||||
descr = dict.__dict__["fromkeys"]
|
||||
# More baseline using the descriptor directly
|
||||
vereq(descr.__get__(None, dict)(arg), res)
|
||||
vereq(descr.__get__({})(arg), res)
|
||||
# Now check various error cases
|
||||
try:
|
||||
descr.__get__(None, None)
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "shouldn't have allowed descr.__get__(None, None)"
|
||||
try:
|
||||
descr.__get__(42)
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "shouldn't have allowed descr.__get__(42)"
|
||||
try:
|
||||
descr.__get__(None, 42)
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "shouldn't have allowed descr.__get__(None, 42)"
|
||||
try:
|
||||
descr.__get__(None, int)
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "shouldn't have allowed descr.__get__(None, int)"
|
||||
|
||||
|
||||
def test_main():
|
||||
do_this_first()
|
||||
|
@ -3819,6 +3858,7 @@ def test_main():
|
|||
mutable_names()
|
||||
subclass_right_op()
|
||||
dict_type_with_metaclass()
|
||||
meth_class_get()
|
||||
|
||||
if verbose: print "All OK"
|
||||
|
||||
|
|
|
@ -57,10 +57,9 @@ wrapper_repr(PyWrapperDescrObject *descr)
|
|||
}
|
||||
|
||||
static int
|
||||
descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
|
||||
PyObject **pres)
|
||||
descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres)
|
||||
{
|
||||
if (obj == NULL || (obj == Py_None && type != Py_None->ob_type)) {
|
||||
if (obj == NULL) {
|
||||
Py_INCREF(descr);
|
||||
*pres = (PyObject *)descr;
|
||||
return 1;
|
||||
|
@ -79,38 +78,69 @@ descr_check(PyDescrObject *descr, PyObject *obj, PyTypeObject *type,
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
classmethod_get(PyMethodDescrObject *descr, PyObject *obj,
|
||||
PyTypeObject *type)
|
||||
classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
|
||||
{
|
||||
return PyCFunction_New(descr->d_method, (PyObject *)type);
|
||||
/* Ensure a valid type. Class methods ignore obj. */
|
||||
if (type == NULL) {
|
||||
if (obj != NULL)
|
||||
type = (PyObject *)obj->ob_type;
|
||||
else {
|
||||
/* Wot - no type?! */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%s' for type '%s' "
|
||||
"needs either an object or a type",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (!PyType_Check(type)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%s' for type '%s' "
|
||||
"needs a type, not a '%s' as arg 2",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name,
|
||||
type->ob_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
if (!PyType_IsSubtype((PyTypeObject *)type, descr->d_type)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%s' for type '%s' "
|
||||
"doesn't apply to type '%s'",
|
||||
descr_name((PyDescrObject *)descr),
|
||||
descr->d_type->tp_name,
|
||||
((PyTypeObject *)type)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
return PyCFunction_New(descr->d_method, type);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
method_get(PyMethodDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||
method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||
if (descr_check((PyDescrObject *)descr, obj, &res))
|
||||
return res;
|
||||
return PyCFunction_New(descr->d_method, obj);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
member_get(PyMemberDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||
member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||
if (descr_check((PyDescrObject *)descr, obj, &res))
|
||||
return res;
|
||||
return PyMember_GetOne((char *)obj, descr->d_member);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||
getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||
if (descr_check((PyDescrObject *)descr, obj, &res))
|
||||
return res;
|
||||
if (descr->d_getset->get != NULL)
|
||||
return descr->d_getset->get(obj, descr->d_getset->closure);
|
||||
|
@ -122,11 +152,11 @@ getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyTypeObject *type)
|
||||
wrapper_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type)
|
||||
{
|
||||
PyObject *res;
|
||||
|
||||
if (descr_check((PyDescrObject *)descr, obj, type, &res))
|
||||
if (descr_check((PyDescrObject *)descr, obj, &res))
|
||||
return res;
|
||||
return PyWrapper_New((PyObject *)descr, obj);
|
||||
}
|
||||
|
@ -395,10 +425,11 @@ static PyTypeObject PyMethodDescr_Type = {
|
|||
0, /* tp_descr_set */
|
||||
};
|
||||
|
||||
/* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */
|
||||
static PyTypeObject PyClassMethodDescr_Type = {
|
||||
PyObject_HEAD_INIT(&PyType_Type)
|
||||
0,
|
||||
"special_method_descriptor",
|
||||
"classmethod_descriptor",
|
||||
sizeof(PyMethodDescrObject),
|
||||
0,
|
||||
(destructor)descr_dealloc, /* tp_dealloc */
|
||||
|
@ -411,7 +442,7 @@ static PyTypeObject PyClassMethodDescr_Type = {
|
|||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
(ternaryfunc)classmethoddescr_call, /* tp_call */
|
||||
(ternaryfunc)classmethoddescr_call, /* tp_call */
|
||||
0, /* tp_str */
|
||||
PyObject_GenericGetAttr, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
|
|
Loading…
Reference in New Issue