mirror of
https://github.com/python/cpython.git
synced 2025-11-03 03:22:27 +00:00
Address SF patch #480716 as well as related issues.
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.
This commit is contained in:
parent
22f9c6ddb8
commit
5b443c6282
2 changed files with 87 additions and 18 deletions
|
|
@ -1572,7 +1572,57 @@ def supers():
|
||||||
def meth(self, a):
|
def meth(self, a):
|
||||||
return "D(%r)" % a + super(D, self).meth(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():
|
def inherits():
|
||||||
if verbose: print "Testing inheritance from basic types..."
|
if verbose: print "Testing inheritance from basic types..."
|
||||||
|
|
|
||||||
|
|
@ -3929,7 +3929,7 @@ super_getattro(PyObject *self, PyObject *name)
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
res = PyDict_GetItem(dict, name);
|
res = PyDict_GetItem(dict, name);
|
||||||
if (res != NULL) {
|
if (res != NULL && !PyDescr_IsData(res)) {
|
||||||
Py_INCREF(res);
|
Py_INCREF(res);
|
||||||
f = res->ob_type->tp_descr_get;
|
f = res->ob_type->tp_descr_get;
|
||||||
if (f != NULL) {
|
if (f != NULL) {
|
||||||
|
|
@ -3944,6 +3944,21 @@ super_getattro(PyObject *self, PyObject *name)
|
||||||
return PyObject_GenericGetAttr(self, 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 *
|
static PyObject *
|
||||||
super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
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);
|
Py_INCREF(self);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
new = (superobject *)PySuper_Type.tp_new(&PySuper_Type, NULL, NULL);
|
if (su->ob_type != &PySuper_Type)
|
||||||
if (new == NULL)
|
/* If su is an instance of a subclass of super,
|
||||||
return NULL;
|
call its type */
|
||||||
Py_INCREF(su->type);
|
return PyObject_CallFunction((PyObject *)su->ob_type,
|
||||||
Py_INCREF(obj);
|
"OO", su->type, obj);
|
||||||
new->type = su->type;
|
else {
|
||||||
new->obj = obj;
|
/* Inline the common case */
|
||||||
return (PyObject *)new;
|
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
|
static int
|
||||||
|
|
@ -3976,15 +4002,8 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
return -1;
|
return -1;
|
||||||
if (obj == Py_None)
|
if (obj == Py_None)
|
||||||
obj = NULL;
|
obj = NULL;
|
||||||
if (obj != NULL &&
|
if (obj != NULL && supercheck(type, obj) < 0)
|
||||||
!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;
|
return -1;
|
||||||
}
|
|
||||||
Py_INCREF(type);
|
Py_INCREF(type);
|
||||||
Py_XINCREF(obj);
|
Py_XINCREF(obj);
|
||||||
su->type = type;
|
su->type = type;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue