]> granicus.if.org Git - python/commitdiff
Put proper tests in classmethod_get(). Remove the type argument to
authorGuido van Rossum <guido@python.org>
Tue, 11 Feb 2003 18:44:42 +0000 (18:44 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 11 Feb 2003 18:44:42 +0000 (18:44 +0000)
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
Objects/descrobject.c

index d7368d32e114b72ddcc1faa86031f72d9c9d70c9..f4812058202721e1a8f4e5e6df9ad00251e7f237 100644 (file)
@@ -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"
 
index 6c78778fd593e7861ac017073a77268d930f0ac7..77ef3599800ef6e7c8641e5acd9434abd0cdec67 100644 (file)
@@ -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 */