mirror of https://github.com/python/cpython
Patch #1623563: allow __class__ assignment for classes with __slots__.
The old and the new class are still required to have the same slot names, but the order in which they are specified is not relevant.
This commit is contained in:
parent
6ab8452036
commit
6f2d09c949
|
@ -1593,6 +1593,11 @@ built-in types such as \class{long}, \class{str} and \class{tuple}.
|
|||
Mappings may also be used; however, in the future, special meaning may
|
||||
be assigned to the values corresponding to each key.
|
||||
|
||||
\item \var{__class__} assignment works only if both classes have the
|
||||
same \var{__slots__}.
|
||||
\versionchanged[Previously, \var{__class__} assignment raised an error
|
||||
if either new or old class had \var{__slots__}]{2.6}
|
||||
|
||||
\end{itemize}
|
||||
|
||||
|
||||
|
@ -2223,3 +2228,6 @@ exception; this is the caller's responsibility.
|
|||
Python \keyword{with} statement.}
|
||||
\end{seealso}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -2853,6 +2853,51 @@ def setclass():
|
|||
cant(o, type(1))
|
||||
cant(o, type(None))
|
||||
del o
|
||||
class G(object):
|
||||
__slots__ = ["a", "b"]
|
||||
class H(object):
|
||||
__slots__ = ["b", "a"]
|
||||
try:
|
||||
unicode
|
||||
except NameError:
|
||||
class I(object):
|
||||
__slots__ = ["a", "b"]
|
||||
else:
|
||||
class I(object):
|
||||
__slots__ = [unicode("a"), unicode("b")]
|
||||
class J(object):
|
||||
__slots__ = ["c", "b"]
|
||||
class K(object):
|
||||
__slots__ = ["a", "b", "d"]
|
||||
class L(H):
|
||||
__slots__ = ["e"]
|
||||
class M(I):
|
||||
__slots__ = ["e"]
|
||||
class N(J):
|
||||
__slots__ = ["__weakref__"]
|
||||
class P(J):
|
||||
__slots__ = ["__dict__"]
|
||||
class Q(J):
|
||||
pass
|
||||
class R(J):
|
||||
__slots__ = ["__dict__", "__weakref__"]
|
||||
|
||||
for cls, cls2 in ((G, H), (G, I), (I, H), (Q, R), (R, Q)):
|
||||
x = cls()
|
||||
x.a = 1
|
||||
x.__class__ = cls2
|
||||
verify(x.__class__ is cls2,
|
||||
"assigning %r as __class__ for %r silently failed" % (cls2, x))
|
||||
vereq(x.a, 1)
|
||||
x.__class__ = cls
|
||||
verify(x.__class__ is cls,
|
||||
"assigning %r as __class__ for %r silently failed" % (cls, x))
|
||||
vereq(x.a, 1)
|
||||
for cls in G, J, K, L, M, N, P, R, list, Int:
|
||||
for cls2 in G, J, K, L, M, N, P, R, list, Int:
|
||||
if cls is cls2:
|
||||
continue
|
||||
cant(cls(), cls2)
|
||||
|
||||
def setdict():
|
||||
if verbose: print "Testing __dict__ assignment..."
|
||||
|
|
|
@ -276,6 +276,7 @@ Chris Herborth
|
|||
Ivan Herman
|
||||
Jürgen Hermann
|
||||
Gary Herron
|
||||
Thomas Herve
|
||||
Bernhard Herzog
|
||||
Magnus L. Hetland
|
||||
Raymond Hettinger
|
||||
|
|
|
@ -12,6 +12,9 @@ What's New in Python 2.6 alpha 1?
|
|||
Core and builtins
|
||||
-----------------
|
||||
|
||||
- Patch #1623563: allow __class__ assignment for classes with __slots__.
|
||||
The old and the new class are still required to have the same slot names.
|
||||
|
||||
- Patch #1642547: Fix an error/crash when encountering syntax errors in
|
||||
complex if statements.
|
||||
|
||||
|
|
|
@ -1844,8 +1844,11 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
|||
}
|
||||
}
|
||||
|
||||
/* Copy slots into yet another tuple, demangling names */
|
||||
newslots = PyTuple_New(nslots - add_dict - add_weak);
|
||||
/* Copy slots into a list, mangle names and sort them.
|
||||
Sorted names are needed for __class__ assignment.
|
||||
Convert them back to tuple at the end.
|
||||
*/
|
||||
newslots = PyList_New(nslots - add_dict - add_weak);
|
||||
if (newslots == NULL)
|
||||
goto bad_slots;
|
||||
for (i = j = 0; i < nslots; i++) {
|
||||
|
@ -1858,13 +1861,23 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
|
|||
tmp =_Py_Mangle(name, tmp);
|
||||
if (!tmp)
|
||||
goto bad_slots;
|
||||
PyTuple_SET_ITEM(newslots, j, tmp);
|
||||
PyList_SET_ITEM(newslots, j, tmp);
|
||||
j++;
|
||||
}
|
||||
assert(j == nslots - add_dict - add_weak);
|
||||
nslots = j;
|
||||
Py_DECREF(slots);
|
||||
slots = newslots;
|
||||
if (PyList_Sort(newslots) == -1) {
|
||||
Py_DECREF(bases);
|
||||
Py_DECREF(newslots);
|
||||
return NULL;
|
||||
}
|
||||
slots = PyList_AsTuple(newslots);
|
||||
Py_DECREF(newslots);
|
||||
if (slots == NULL) {
|
||||
Py_DECREF(bases);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Secondary bases may provide weakrefs or dict */
|
||||
if (nbases > 1 &&
|
||||
|
@ -2481,6 +2494,7 @@ same_slots_added(PyTypeObject *a, PyTypeObject *b)
|
|||
{
|
||||
PyTypeObject *base = a->tp_base;
|
||||
Py_ssize_t size;
|
||||
PyObject *slots_a, *slots_b;
|
||||
|
||||
if (base != b->tp_base)
|
||||
return 0;
|
||||
|
@ -2491,6 +2505,15 @@ same_slots_added(PyTypeObject *a, PyTypeObject *b)
|
|||
size += sizeof(PyObject *);
|
||||
if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size)
|
||||
size += sizeof(PyObject *);
|
||||
|
||||
/* Check slots compliance */
|
||||
slots_a = ((PyHeapTypeObject *)a)->ht_slots;
|
||||
slots_b = ((PyHeapTypeObject *)b)->ht_slots;
|
||||
if (slots_a && slots_b) {
|
||||
if (PyObject_Compare(slots_a, slots_b) != 0)
|
||||
return 0;
|
||||
size += sizeof(PyObject *) * PyTuple_GET_SIZE(slots_a);
|
||||
}
|
||||
return size == a->tp_basicsize && size == b->tp_basicsize;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue