[Zodb-checkins] CVS: Zope3/src/persistence - persistence.c:1.10
Jeremy Hylton
jeremy@zope.com
Thu, 3 Apr 2003 19:00:20 -0500
Update of /cvs-repository/Zope3/src/persistence
In directory cvs.zope.org:/tmp/cvs-serv26419
Modified Files:
persistence.c
Log Message:
Don't unghostify an object for __del__.
Persistent objects are often in cycles -- they point to their data
manager and their data manager points to them. Python 2.2 will look
for an __del__ attribute on an instance that is unreachable. We don't
want to unghostify an object in this case.
XXX Should enforce the policy that Persistent objects can't have an
__del__.
XXX Must backport to Zope2.
=== Zope3/src/persistence/persistence.c 1.9 => 1.10 ===
--- Zope3/src/persistence/persistence.c:1.9 Wed Apr 2 18:07:00 2003
+++ Zope3/src/persistence/persistence.c Thu Apr 3 19:00:20 2003
@@ -15,6 +15,7 @@
#include "structmember.h"
#include "persistence.h"
+
static char PyPersist_doc_string[] =
"Defines Persistent mixin class for persistent objects.\n"
"\n"
@@ -84,6 +85,7 @@
meth = PyObject_GetAttr((PyObject *)self->po_dm, s_setstate);
if (meth == NULL)
return 0;
+
arg = PyTuple_New(1);
if (arg == NULL) {
Py_DECREF(meth);
@@ -91,9 +93,12 @@
}
Py_INCREF(self);
PyTuple_SET_ITEM(arg, 0, (PyObject *)self);
+
result = PyObject_Call(meth, arg, NULL);
+
Py_DECREF(arg);
Py_DECREF(meth);
+
if (result) {
Py_DECREF(result);
return 1;
@@ -367,11 +372,49 @@
tp_setattr hooks, which allow the persistence machinery to
automatically detect changes to and accesses of the object's state.
+ In general, if getattr() is called on a ghost, the data manager
+ must load the ghost's state before calling PyObject_GenericGetAttr().
+ There are several special attributes that ignore this rule.
+
The current implemenation probably isn't right, because it doesn't
even attempt to deal with a persistent classes that defines its own
__getattr__ or __getattribute__.
*/
+/* Returns true if the object requires unghostification.
+
+ Don't unghostify for any attribute starting with _p_. The Python
+ special names __del__, __dict__, and __class__ are also exempt.
+*/
+
+static int
+persist_checkattr(const char *s)
+{
+ if (*s++ != '_')
+ return 1;
+ if (*s == 'p') {
+ s++;
+ if (*s == '_')
+ return 0; /* _p_ */
+ else
+ return 1;
+ }
+ else if (*s == '_') {
+ s++;
+ if (*s == 'd') {
+ s++;
+ if (!strncmp(s, "ict__", 5))
+ return 0; /* __dict__ */
+ if (!strncmp(s, "el__", 4))
+ return 0; /* __del__ */
+ return 1;
+ }
+ else if (!strncmp(s, "class__", 7))
+ return 0; /* __class__ */
+ }
+ return 1;
+}
+
static PyObject *
persist_getattro(PyPersistObject *self, PyObject *name)
{
@@ -392,10 +435,7 @@
XXX Don't revive a ghost just to get its __class__.
*/
- if ((s_name[0] != '_') ||
- ((strncmp(s_name, "_p_", 3) != 0) &&
- (strcmp(s_name, "__dict__") != 0) &&
- (strcmp(s_name, "__class__") != 0))) {
+ if (persist_checkattr(s_name)) {
if (self->po_state == GHOST) {
/* Prevent the object from being registered as changed.
@@ -514,6 +554,7 @@
}
r = PyObject_GenericSetAttr((PyObject *)self, name, value);
Py_DECREF(name);
+
return r;
}