FWIW, __setstate__ for Zope objects has typically been used as a "one-way" kind of backwards compatibility mechanism (where the object's database state remains unmodified, but the in-memory state is changed) not only for the reasons that Tim just explained, but also because changing the persistent state of an object as a side effect of unghosting would can be a bad idea anyway. ZODB writes can be very expensive and having them occur as side effects of loading state from the database could be problematic in some circumstances. This is commonly referred to as the "write on read" pattern and is largely discouraged. Tim pointed at a proposal by Jim which aims to allow for orderly upgrade of database state based on developer-defined schema versions where the upgrade is done at known times (like, when someone presses a button, or at Zope startup time) which seems saner.
There is an (experimental) Zope 2 product that implements the pattern in Jim's proposal (using mostly the same code that Zope 3 uses for its experimental implementation of the same) available at http://cvs.zope.org/Products/zzz_generations/ On Fri, 2004-05-28 at 14:51, Tim Peters wrote: > [Syver Enstad, wants to switch an attribute of a Persitent subclass > From PersistentList to an IOBTree] > > [Tim, guessing] > > Quick guess (untested, untried, ... > ... > > Perhaps shuffling the code around would work, a la: > > > > Persistent.__setstate__(self, state) > > articleList = state.get('_articleList') > > if articleList is not None: > > # make the BTree in local oidsToArticles as above, then > > del self._articlelist > > self._oidsToArticles = oidsToArticles > > > > The thinking there is that then you've truly modified self, after self has > > been activated. > > Nope, sorry, not a chance. You have truly modified self then, but > __setstate__ is called by magic as part of activation (unghostifying), and > the activation machinery resets self._p_changed after it calls __setstate__. > So same result as your code: the in-memory version of self has the BTree, > but commit() doesn't change anything about self in the database (again > because self._p_changed is false -- and will be no matter what you try to do > in __setstate__()). > > This appears to be one of those "severely underdocumented" minefields. The > best older thread I found is here: > > http://mail.zope.org/pipermail/zodb-dev/2002-March/002442.html > > but it doesn't actually spell out something "that works" in the way you > want. > > One possibility is to use any of these __setstate__ implementations > temporarily, in a one-shot database conversion script: load every object of > your subclass's type, and for each one "obj", after loading it do > > obj._p_changed = True > get_transaction().commit() > > Note again that setting _p_changed *inside* __setstate__ won't do any good. > > Note too that Jim Fulton has a recent proposal for Zope3 in this area: > > http://tinyurl.com/ypkhk > > [Zope URLs are generally so long my mailer refuses to keep them on one line] > > > _______________________________________________ > Zope-Dev maillist - [EMAIL PROTECTED] > http://mail.zope.org/mailman/listinfo/zope-dev > ** No cross posts or HTML encoding! ** > (Related lists - > http://mail.zope.org/mailman/listinfo/zope-announce > http://mail.zope.org/mailman/listinfo/zope ) _______________________________________________ Zope-Dev maillist - [EMAIL PROTECTED] http://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - http://mail.zope.org/mailman/listinfo/zope-announce http://mail.zope.org/mailman/listinfo/zope )