[Zodb-checkins] CVS: ZODB4/src/persistence - persistence.c:1.12

Phillip J. Eby pje@telecommunity.com
Fri, 11 Apr 2003 18:00:24 -0400


Update of /cvs-repository/ZODB4/src/persistence
In directory cvs.zope.org:/tmp/cvs-serv7086/src/persistence

Modified Files:
	persistence.c 
Log Message:
Fixed the last two bugs from Zope3-Dev Collector #86: you couldn't mix
Persistent and a base class that used a Python metaclass under Python 2.2,
and Persistent subclasses wouldn't have instance dictionaries if a parent
class defined '__slots__', even though for normal Python classes, 
subclassing a class with '__slots__' produces a class with instance
dictionaries unless the subclass also defines '__slots__'.  Added test
cases for both scenarios.  Note that these bugs only existed under Python
2.2, where the custom C metaclass 'PersistentMetaClass' is used.


=== ZODB4/src/persistence/persistence.c 1.11 => 1.12 ===
--- ZODB4/src/persistence/persistence.c:1.11	Thu Apr 10 13:55:25 2003
+++ ZODB4/src/persistence/persistence.c	Fri Apr 11 17:59:54 2003
@@ -840,9 +840,11 @@
 
     /* It is possible for a class that inherits from Persistent to
        define __slots__, in which case it shouldn't have a dict.
-       XXX This isn't ready yet.
+       We have to look in the dictionary supplied to the keyword arguments,
+       however, or we can be fooled by a base type having __slots__.
+       (See 'persistence.tests.test_persistence.Test.testSlots')
     */
-    if (PyObject_HasAttrString((PyObject *)new, "__slots__")) {
+    if (PyMapping_HasKeyString(PyTuple_GetItem(args,2), "__slots__")) {
 	return (PyObject *)new;
     }
 
@@ -971,6 +973,16 @@
     PyPersist_MetaType.tp_clear = PyType_Type.tp_clear;
     if (PyType_Ready(&PyPersist_MetaType) < 0)
 	return;
+
+    /* Cheap hack to force us to be used instead of 'type' as '__base__';
+       this ensures that we are always used for C-level layout, and can
+       therefore interoperate with other (pure Python) metaclasses.
+       (See 'persistence.tests.test_persistence.Test.testMultipleMeta')
+       This costs us a (PyObject *) per subclass of Persistent, but it
+       seems to be the only way to fix this in Python 2.2.x.  :(
+    */
+    PyPersist_MetaType.tp_basicsize += sizeof(PyObject *);
+
     Py_INCREF(&PyPersist_MetaType);
     if (PyDict_SetItemString(d, "PersistentMetaClass", 
 			     (PyObject *)&PyPersist_MetaType) < 0)