[Zope-dev] Help: __getstate__ overriding

Chris McDonough chrism at plope.com
Fri May 28 15:20:06 EDT 2004


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  -  Zope-Dev at zope.org
> 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 )




More information about the Zope-Dev mailing list