[Python-checkins] r54412 - in python/trunk: Doc/ref/ref3.tex Lib/test/test_descr.py Misc/ACKS Misc/NEWS Objects/typeobject.c

ziga.seilnacht python-checkins at python.org
Fri Mar 16 12:59:44 CET 2007


Author: ziga.seilnacht
Date: Fri Mar 16 12:59:38 2007
New Revision: 54412

Modified:
   python/trunk/Doc/ref/ref3.tex
   python/trunk/Lib/test/test_descr.py
   python/trunk/Misc/ACKS
   python/trunk/Misc/NEWS
   python/trunk/Objects/typeobject.c
Log:
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.

Modified: python/trunk/Doc/ref/ref3.tex
==============================================================================
--- python/trunk/Doc/ref/ref3.tex	(original)
+++ python/trunk/Doc/ref/ref3.tex	Fri Mar 16 12:59:38 2007
@@ -1593,6 +1593,11 @@
 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 @@
           Python \keyword{with} statement.}
 \end{seealso}
 
+
+
+

Modified: python/trunk/Lib/test/test_descr.py
==============================================================================
--- python/trunk/Lib/test/test_descr.py	(original)
+++ python/trunk/Lib/test/test_descr.py	Fri Mar 16 12:59:38 2007
@@ -2853,6 +2853,51 @@
     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..."

Modified: python/trunk/Misc/ACKS
==============================================================================
--- python/trunk/Misc/ACKS	(original)
+++ python/trunk/Misc/ACKS	Fri Mar 16 12:59:38 2007
@@ -276,6 +276,7 @@
 Ivan Herman
 Jürgen Hermann
 Gary Herron
+Thomas Herve
 Bernhard Herzog
 Magnus L. Hetland
 Raymond Hettinger

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Fri Mar 16 12:59:38 2007
@@ -12,6 +12,9 @@
 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.
 

Modified: python/trunk/Objects/typeobject.c
==============================================================================
--- python/trunk/Objects/typeobject.c	(original)
+++ python/trunk/Objects/typeobject.c	Fri Mar 16 12:59:38 2007
@@ -1844,8 +1844,11 @@
 			}
 		}
 
-		/* 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 @@
 			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 @@
 {
 	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 @@
 		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;
 }
 


More information about the Python-checkins mailing list