]> granicus.if.org Git - python/commitdiff
Address SF patch #480716 as well as related issues.
authorGuido van Rossum <guido@python.org>
Mon, 3 Dec 2001 15:38:28 +0000 (15:38 +0000)
committerGuido van Rossum <guido@python.org>
Mon, 3 Dec 2001 15:38:28 +0000 (15:38 +0000)
SF patch #480716 by Greg Chapman fixes the problem that super's
__get__ method always returns an instance of super, even when the
instance whose __get__ method is called is an instance of a subclass
of super.

Other issues fixed:

- super(C, C()).__class__ would return the __class__ attribute of C()
  rather than the __class__ attribute of the super object.  This is
  confusing.  To fix this, I decided to change the semantics of super
  so that it only applies to code attributes, not to data attributes.
  After all, overriding data attributes is not supported anyway.

- While super(C, x) carefully checked that x is an instance of C,
  super(C).__get__(x) made no such check, allowing for a loophole.
  This is now fixed.

Lib/test/test_descr.py
Objects/typeobject.c

index 8166d7c5d986f15119cd4e0b71e5d407d3720797..f3b81ac57819cecd7ca43b879a80f0924e20b4f2 100644 (file)
@@ -1572,7 +1572,57 @@ def supers():
         def meth(self, a):
             return "D(%r)" % a + super(D, self).meth(a)
 
-    verify (D().meth(4) == "D(4)C(4)B(4)A(4)")
+    vereq(D().meth(4), "D(4)C(4)B(4)A(4)")
+
+    # Test for subclassing super
+
+    class mysuper(super):
+        def __init__(self, *args):
+            return super(mysuper, self).__init__(*args)
+
+    class E(D):
+        def meth(self, a):
+            return "E(%r)" % a + mysuper(E, self).meth(a)
+
+    vereq(E().meth(5), "E(5)D(5)C(5)B(5)A(5)")
+
+    class F(E):
+        def meth(self, a):
+            s = self.__super
+            return "F(%r)[%s]" % (a, s.__class__.__name__) + s.meth(a)
+    F._F__super = mysuper(F)
+
+    vereq(F().meth(6), "F(6)[mysuper]E(6)D(6)C(6)B(6)A(6)")
+
+    # Make sure certain errors are raised
+
+    try:
+        super(D, 42)
+    except TypeError:
+        pass
+    else:
+        raise TestFailed, "shouldn't allow super(D, 42)"
+
+    try:
+        super(D, C())
+    except TypeError:
+        pass
+    else:
+        raise TestFailed, "shouldn't allow super(D, C())"
+
+    try:
+        super(D).__get__(12)
+    except TypeError:
+        pass
+    else:
+        raise TestFailed, "shouldn't allow super(D).__get__(12)"
+
+    try:
+        super(D).__get__(C())
+    except TypeError:
+        pass
+    else:
+        raise TestFailed, "shouldn't allow super(D).__get__(C())"
 
 def inherits():
     if verbose: print "Testing inheritance from basic types..."
index c79636dd69575e26499afa24847d0bf178e78bfd..6fc5d027bc0bd86fb2ff057c955ea3ec33f1fef5 100644 (file)
@@ -3929,7 +3929,7 @@ super_getattro(PyObject *self, PyObject *name)
                        else
                                continue;
                        res = PyDict_GetItem(dict, name);
-                       if (res != NULL) {
+                       if (res != NULL  && !PyDescr_IsData(res)) {
                                Py_INCREF(res);
                                f = res->ob_type->tp_descr_get;
                                if (f != NULL) {
@@ -3944,6 +3944,21 @@ super_getattro(PyObject *self, PyObject *name)
        return PyObject_GenericGetAttr(self, name);
 }
 
+static int
+supercheck(PyTypeObject *type, PyObject *obj)
+{
+       if (!PyType_IsSubtype(obj->ob_type, type) &&
+           !(PyType_Check(obj) &&
+             PyType_IsSubtype((PyTypeObject *)obj, type))) {
+               PyErr_SetString(PyExc_TypeError,
+                       "super(type, obj): "
+                       "obj must be an instance or subtype of type");
+               return -1;
+       }
+       else
+               return 0;
+}
+
 static PyObject *
 super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
 {
@@ -3955,14 +3970,25 @@ super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
                Py_INCREF(self);
                return self;
        }
-       new = (superobject *)PySuper_Type.tp_new(&PySuper_Type, NULL, NULL);
-       if (new == NULL)
-               return NULL;
-       Py_INCREF(su->type);
-       Py_INCREF(obj);
-       new->type = su->type;
-       new->obj = obj;
-       return (PyObject *)new;
+       if (su->ob_type != &PySuper_Type)
+               /* If su is an instance of a subclass of super,
+                  call its type */
+               return PyObject_CallFunction((PyObject *)su->ob_type,
+                                            "OO", su->type, obj);
+       else {
+               /* Inline the common case */
+               if (supercheck(su->type, obj) < 0)
+                       return NULL;
+               new = (superobject *)PySuper_Type.tp_new(&PySuper_Type,
+                                                        NULL, NULL);
+               if (new == NULL)
+                       return NULL;
+               Py_INCREF(su->type);
+               Py_INCREF(obj);
+               new->type = su->type;
+               new->obj = obj;
+               return (PyObject *)new;
+       }
 }
 
 static int
@@ -3976,15 +4002,8 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
                return -1;
        if (obj == Py_None)
                obj = NULL;
-       if (obj != NULL &&
-           !PyType_IsSubtype(obj->ob_type, type) &&
-           !(PyType_Check(obj) &&
-             PyType_IsSubtype((PyTypeObject *)obj, type))) {
-               PyErr_SetString(PyExc_TypeError,
-                       "super(type, obj): "
-                       "obj must be an instance or subtype of type");
+       if (obj != NULL && supercheck(type, obj) < 0)
                return -1;
-       }
        Py_INCREF(type);
        Py_XINCREF(obj);
        su->type = type;