From b6e5a0c6587420ba666d5402a8aefd20b9f8c507 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 11 Feb 2003 18:44:42 +0000 Subject: 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. --- Lib/test/test_descr.py | 40 ++++++++++++++++++++++++++++++++ Objects/descrobject.c | 63 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index d7368d3..f481205 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -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" diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 6c78778..77ef359 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -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 */ -- cgit v0.12