]> granicus.if.org Git - python/commitdiff
properly lookup __instancecheck__ and __subclasscheck__
authorBenjamin Peterson <benjamin@python.org>
Sat, 16 May 2009 21:44:25 +0000 (21:44 +0000)
committerBenjamin Peterson <benjamin@python.org>
Sat, 16 May 2009 21:44:25 +0000 (21:44 +0000)
Lib/test/test_descr.py
Objects/abstract.c
Objects/typeobject.c

index e66b550ce4a6a27e614fdaaf06e56724c13b97a6..f3c216a39cc7d081bfe2f8acc2ccf881361474ed 100644 (file)
@@ -1683,16 +1683,25 @@ order (MRO) for bases """
             return 0
         def stop(self):
             raise StopIteration
+        def return_true(self, thing=None):
+            return True
+        def do_isinstance(obj):
+            return isinstance(int, obj)
+        def do_issubclass(obj):
+            return issubclass(int, obj)
 
         # It would be nice to have every special method tested here, but I'm
         # only listing the ones I can remember outside of typeobject.c, since it
         # does it right.
         specials = [
-            ("__unicode__", unicode, hello, {}),
-            ("__reversed__", reversed, empty_seq, {}),
-            ("__length_hint__", list, zero,
+            ("__unicode__", unicode, hello, set(), {}),
+            ("__reversed__", reversed, empty_seq, set(), {}),
+            ("__length_hint__", list, zero, set(),
              {"__iter__" : iden, "next" : stop}),
-            ("__sizeof__", sys.getsizeof, zero, {}),
+            ("__sizeof__", sys.getsizeof, zero, set(), {}),
+            ("__instancecheck__", do_isinstance, return_true, set(), {}),
+            ("__subclasscheck__", do_issubclass, return_true,
+             set(("__bases__",)), {}),
             # These two fail because the compiler generates LOAD_ATTR to look
             # them up.  We'd have to add a new opcode to fix this, and it's
             # probably not worth it.
@@ -1704,7 +1713,9 @@ order (MRO) for bases """
             def __getattr__(self, attr, test=self):
                 test.fail("__getattr__ called with {0}".format(attr))
             def __getattribute__(self, attr, test=self):
-                test.fail("__getattribute__ called with {0}".format(attr))
+                if attr not in ok:
+                    test.fail("__getattribute__ called with {0}".format(attr))
+                return object.__getattribute__(attr)
         class SpecialDescr(object):
             def __init__(self, impl):
                 self.impl = impl
@@ -1713,7 +1724,7 @@ order (MRO) for bases """
                 return self.impl.__get__(obj, owner)
 
 
-        for name, runner, meth_impl, env in specials:
+        for name, runner, meth_impl, ok, env in specials:
             class X(Checker):
                 pass
             for attr, obj in env.iteritems():
index 4da7e0035eacfd5c63f9f99de04825e1b1a96675..5fb7bfc01e17af36aed4a6ea61a761d6f30608d9 100644 (file)
@@ -2926,14 +2926,19 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
                Py_LeaveRecursiveCall();
                return r;
        }
-       if (name == NULL) {
-               name = PyString_InternFromString("__instancecheck__");
-               if (name == NULL)
-                       return -1;
+
+       if (PyInstance_Check(cls)) {
+               checker = PyObject_GetAttrString(cls, "__instancecheck__");
+               if (checker == NULL) {
+                       if (PyErr_ExceptionMatches(PyExc_AttributeError))
+                               PyErr_Clear();
+                       else
+                               return -1;
+               }
+       }
+       else {
+               checker = _PyObject_LookupSpecial(cls, "__instancecheck__", &name);
        }
-       checker = PyObject_GetAttr(cls, name);
-       if (checker == NULL && PyErr_Occurred())
-               PyErr_Clear();
        if (checker != NULL) {
                PyObject *res;
                int ok = -1;
@@ -3008,14 +3013,21 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls)
                Py_LeaveRecursiveCall();
                return r;
        }
-       if (name == NULL) {
-               name = PyString_InternFromString("__subclasscheck__");
-               if (name == NULL)
+       if (PyInstance_Check(cls)) {
+               PyErr_Fetch(&t, &v, &tb);
+               checker = PyObject_GetAttr(cls, name);
+               if (checker == NULL &&
+                   !PyErr_ExceptionMatches(PyExc_AttributeError)) {
+                       Py_XDECREF(t);
+                       Py_XDECREF(v);
+                       Py_XDECREF(tb);
                        return -1;
+               }
+               PyErr_Restore(t, v, tb);
+       }
+       else {
+               checker = _PyObject_LookupSpecial(cls, "__subclasscheck__", &name);
        }
-       PyErr_Fetch(&t, &v, &tb);
-       checker = PyObject_GetAttr(cls, name);
-       PyErr_Restore(t, v, tb);
        if (checker != NULL) {
                PyObject *res;
                int ok = -1;
index fabdd9db1451aaec14f9a8fda770a8d0cec8ac65..8c49096216d7c7e0e11dba6b701df53087b3e481 100644 (file)
@@ -585,14 +585,6 @@ type___instancecheck__(PyObject *type, PyObject *inst)
 }
 
 
-static PyObject *
-type_get_instancecheck(PyObject *type, void *context)
-{
-       static PyMethodDef ml = {"__instancecheck__",
-                                type___instancecheck__, METH_O };
-       return PyCFunction_New(&ml, type);
-}
-
 static PyObject *
 type___subclasscheck__(PyObject *type, PyObject *inst)
 {
@@ -606,13 +598,6 @@ type___subclasscheck__(PyObject *type, PyObject *inst)
        }
 }
 
-static PyObject *
-type_get_subclasscheck(PyObject *type, void *context)
-{
-       static PyMethodDef ml = {"__subclasscheck__",
-                                type___subclasscheck__, METH_O };
-       return PyCFunction_New(&ml, type);
-}
 
 static PyGetSetDef type_getsets[] = {
        {"__name__", (getter)type_name, (setter)type_set_name, NULL},
@@ -622,8 +607,6 @@ static PyGetSetDef type_getsets[] = {
         (setter)type_set_abstractmethods, NULL},
        {"__dict__",  (getter)type_dict,  NULL, NULL},
        {"__doc__", (getter)type_get_doc, NULL, NULL},
-       {"__instancecheck__", (getter)type_get_instancecheck, NULL, NULL},
-       {"__subclasscheck__", (getter)type_get_subclasscheck, NULL, NULL},
        {0}
 };
 
@@ -2674,6 +2657,10 @@ static PyMethodDef type_methods[] = {
         PyDoc_STR("mro() -> list\nreturn a type's method resolution order")},
        {"__subclasses__", (PyCFunction)type_subclasses, METH_NOARGS,
         PyDoc_STR("__subclasses__() -> list of immediate subclasses")},
+       {"__instancecheck__", type___instancecheck__, METH_O,
+        PyDoc_STR("__instancecheck__() -> check if an object is an instance")},
+       {"__subclasscheck__", type___subclasscheck__, METH_O,
+        PyDoc_STR("__subclasschck__ -> check if an class is a subclass")},
        {0}
 };