diff options
-rw-r--r-- | Lib/test/test_descr.py | 52 | ||||
-rw-r--r-- | Objects/typeobject.c | 53 |
2 files changed, 87 insertions, 18 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 8166d7c..f3b81ac 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -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..." diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c79636d..6fc5d02 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -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; |