]> granicus.if.org Git - python/commitdiff
SF #532767: isinstance(x, X) should work when x is a proxy for an X
authorGuido van Rossum <guido@python.org>
Wed, 12 Feb 2003 03:32:58 +0000 (03:32 +0000)
committerGuido van Rossum <guido@python.org>
Wed, 12 Feb 2003 03:32:58 +0000 (03:32 +0000)
instance, as long as x.__class__ is X or a subclass thereof.
Did a little cleanup of PyObject_IsInstance() too.

Lib/test/test_descr.py
Misc/NEWS
Objects/abstract.c

index f4812058202721e1a8f4e5e6df9ad00251e7f237..75ad135b5a28311387f05d287d8dcdfdf26fc292 100644 (file)
@@ -3735,7 +3735,8 @@ def dict_type_with_metaclass():
 
 def meth_class_get():
     # Full coverage of descrobject.c::classmethod_get()
-    if verbose: print "Testing __get__ method of METH_CLASS C methods..."
+    if verbose:
+        print "Testing __get__ method of METH_CLASS C methods..."
     # Baseline
     arg = [1, 2, 3]
     res = {1: None, 2: None, 3: None}
@@ -3772,6 +3773,32 @@ def meth_class_get():
     else:
         raise TestFailed, "shouldn't have allowed descr.__get__(None, int)"
 
+def isinst_isclass():
+    if verbose:
+        print "Testing proxy isinstance() and isclass()..."
+    class Proxy(object):
+        def __init__(self, obj):
+            self.__obj = obj
+        def __getattribute__(self, name):
+            if name.startswith("_Proxy__"):
+                return object.__getattribute__(self, name)
+            else:
+                return getattr(self.__obj, name)
+    # Test with a classic class
+    class C:
+        pass
+    a = C()
+    pa = Proxy(a)
+    verify(isinstance(a, C))  # Baseline
+    verify(isinstance(pa, C)) # Test
+    # Test with a new-style class
+    class C(object):
+        pass
+    a = C()
+    pa = Proxy(a)
+    verify(isinstance(a, C))  # Baseline
+    verify(isinstance(pa, C)) # Test
+
 
 def test_main():
     do_this_first()
@@ -3859,6 +3886,7 @@ def test_main():
     subclass_right_op()
     dict_type_with_metaclass()
     meth_class_get()
+    isinst_isclass()
 
     if verbose: print "All OK"
 
index ed4f7cf9ac0ea885dd164a234b6facb72edf0f59..d88f7533461af5ce5b69d42b78eacafe2bf2986d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,11 @@ What's New in Python 2.3 alpha 2?
 Core and builtins
 -----------------
 
+- isinstance(x, X): if X is a new-style class, this is now equivalent
+  to issubclass(type(x), X) or issubclass(x.__class__, X).  Previously
+  only type(x) was tested.  (For classic classes this was already the
+  case.)
+
 - compile(), eval() and the exec statement now fully support source code
   passed as unicode strings.
 
index abc7e709bbb85199aa0ac038b2c68307acafea7e..45d22069dbfef255606ee63ba48ddf86b5eb2e2c 100644 (file)
@@ -2040,6 +2040,12 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
        static PyObject *__class__ = NULL;
        int retval = 0;
 
+       if (__class__ == NULL) {
+               __class__ = PyString_FromString("__class__");
+               if (__class__ == NULL)
+                       return -1;
+       }
+
        if (PyClass_Check(cls) && PyInstance_Check(inst)) {
                PyObject *inclass =
                        (PyObject*)((PyInstanceObject*)inst)->in_class;
@@ -2047,6 +2053,19 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
        }
        else if (PyType_Check(cls)) {
                retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls);
+               if (retval == 0) {
+                       PyObject *c = PyObject_GetAttr(inst, __class__);
+                       if (c == NULL) {
+                               PyErr_Clear();
+                       }
+                       else {
+                               if (c != inst->ob_type && PyType_Check(c))
+                                       retval = PyType_IsSubtype(
+                                               (PyTypeObject *)c,
+                                               (PyTypeObject *)cls);
+                               Py_DECREF(c);
+                       }
+               }
        }
        else if (PyTuple_Check(cls)) {
                /* Not a general sequence -- that opens up the road to
@@ -2060,18 +2079,12 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls)
                        if (retval != 0)
                                break;
                }
-               return retval;
        }
        else {
                if (!check_class(cls,
                        "isinstance() arg 2 must be a class, type,"
                        " or tuple of classes and types"))
                        return -1;
-               if (__class__ == NULL) {
-                       __class__ = PyString_FromString("__class__");
-                       if (__class__ == NULL)
-                               return -1;
-               }
                icls = PyObject_GetAttr(inst, __class__);
                if (icls == NULL) {
                        PyErr_Clear();