[Zope] persistence and dictionaries
Jonothan Farr
jfarr@real.com
Fri, 8 Dec 2000 13:15:39 -0800
Maybe I'm mistaken, but it seems like you can put an instance of an object that
doesn't inherit from Persistent into the ZODB just fine, but its contents won't
persist, so you'll always end up with a copy of the object as it was first added
to the database.
--jfarr
----- Original Message -----
From: "Chris McDonough" <chrism@digicool.com>
To: <matt.bion@eudoramail.com>
Cc: <zope@zope.org>
Sent: Friday, December 08, 2000 11:57 AM
Subject: Re: [Zope] persistence and dictionaries
> Huh. If they do, it's by chance only. I'd be hard-pressed to explain it.
>
> Do they inherit from *anything*?
>
> ----- Original Message -----
> From: "Matt" <matt.bion@eudoramail.com>
> To: "Chris McDonough" <chrism@digicool.com>
> Cc: <zope@zope.org>
> Sent: Friday, December 08, 2000 2:30 PM
> Subject: Re: [Zope] persistence and dictionaries
>
>
> > Chris, this was my original confusion .... the two places below where you
> say
> >
> > "You can put instances which do not inherit from Persistence.Persistent in
> > your database. They just won't "stick". They'll hang around until the
> > server is restarted or for an undetermined amount of time during normal
> > operations."
> >
> > "No. It'll work for "a while" or until the server is restarted. :-)"
> >
> > actually do persist after restarts ... that's what confused me, they
> wouldn't
> > go away and they should!!
> >
> > regards
> > Matt
> >
> > Chris McDonough wrote:
> >
> > > > Thanks for the reply, that is really useful. There are a couple of
> things
> > > > though that still don't add up. Firstly, you say below, as do all the
> > > ZODB
> > > > documents that "Custom" classes can certainly persist, they just need
> to
> > > mix in
> > > > the "Persistence.Persistent" class as a base class. Well, in my
> example I
> > > > attached in my first email, my product certainly has
> > > Persistence.Persistent,
> > > > but my second class that I add to this one does not, yet it still
> > > persists.
> > > > There was an email sometime ago on the mailing list that told someone
> that
> > > this
> > > > was why their product instances disappearing from the ZODB.
> > > > (the ref for the original email is :
> > > http://www.egroups.com/message/zope/44263
> > > > ... I can't find the reply again.)
> > > >
> > >
> > > You can put instances which do not inherit from Persistence.Persistent
> in
> > > your database. They just won't "stick". They'll hang around until the
> > > server is restarted or for an undetermined amount of time during normal
> > > operations.
> > >
> > > > So my current understanding would be that any classes you want to add
> in
> > > do not
> > > > need to derive from Persistence.Persistent, and if it is pickleable
> then
> > > all
> > > > should be fine if you call on instances of that object within you
> product.
> > >
> > > No. It'll work for "a while" or until the server is restarted. :-)
> > >
> > > > The next part that worried me came from the "python product tutorial"
> > > > http://www.zope.org/Members/hathawsh/PythonProductTutorial
> > > >
> > > > This stated that the class dictionary self.votes = {} needed to be
> changed
> > > to
> > > > self._votes = Globals.PersistentMapping() so that updates to it
> persist.
> > > > Hence my query about dictionaries.
> > >
> > > This was for convenience, I'd imagine.
> > >
> > > > I also noticed your comment about __setstate__ . What is it about
> this
> > > that is
> > > > dangerous.
> > >
> > > Nothing implicitly dangerous, but it can get confusing if you have
> multiple
> > > revisions of your product and you use variables caused by __setstate__.
> > > Also, once you add a __setstate__ which modifies the object in-place,
> > > there's a likelihood that it can never go away (you're can never be sure
> if
> > > all instances have been updated).
> > >
> > > > Recently I built a product out of some python classes I wrapped
> > > > around 4DOM, and since 4DOM documents do not seem to persist(well the
> > > document
> > > > does, but it loses all its children), then I persisted them to the
> local
> > > file
> > > > system, since I needed to do that anyway for what I was doing.
> Setstate
> > > seemed
> > > > to work nicely to bring them back, though watching its behaviour I
> noticed
> > > that
> > > > it was called very often by zope.
> > >
> > > Sure, that works... although at that point you're creating your own
> object
> > > database. :-)
> > >
> > > >
> > > > Chris McDonough wrote:
> > > >
> > > > > All pickleable Python primitive types (strings, dictionaries, lists,
> > > Nones,
> > > > > integers, floats, longs, etc.) can live in the ZODB. They can
> persist
> > > just
> > > > > like instances that inherit from the Persistent class.
> > > > >
> > > > > I think you read a little too much in to the fact that you need to
> > > "treat
> > > > > mutable objects immutably" when working with them in the ZODB. This
> > > > > statement doesn't mean that these kinds of objects can't be saved in
> the
> > > > > ZODB, it just means you need to treat them specially when putting
> them
> > > in
> > > > > the database.
> > > > >
> > > > > For instance, if you were doing this inside of an external method:
> > > > >
> > > > > def amethod(self):
> > > > > self.mydict = {}
> > > > > self.mydict['a'] = 1
> > > > >
> > > > > (where self is the persistent object that is usually the external
> > > method's
> > > > > "container")
> > > > >
> > > > > It wouldn't work as you expected. Although you'd see an 'a' in
> mydict
> > > for a
> > > > > little while in further accesses to it, 'mydict' would eventaully
> show
> > > up as
> > > > > an empty dictionary on the first access of it after it was expired
> from
> > > the
> > > > > RAM cache (after it was 'ghosted'), because the last thing that the
> ZODB
> > > > > "saw" (via the __setattr__ on 'self' and a subsequent transaction)
> was
> > > you
> > > > > setting a empty dictionary.
> > > > >
> > > > > Persistent objects (like "self" in the above example) are only smart
> > > enough
> > > > > to notice changes to themselves that happen through their
> __setattr__
> > > (e.g.
> > > > > self.mydict = {} calls self's __setattr__). Mutating the attribute
> > > 'mydict'
> > > > > above "in-place" (via self.mydict['a'] = 1) does not trigger self's
> > > > > __setattr__, so the ZODB never notices that "mydict" got changed.
> > > > >
> > > > > There are two ways to handle this. The first is to treat mutable
> > > attributes
> > > > > "immutably" via assigning to a temporary variable and then making
> sure
> > > the
> > > > > persistent container's __setattr__ gets called:
> > > > >
> > > > > def amethod(self):
> > > > > dict = {}
> > > > > dict['a'] = 1
> > > > > self.mydict = dict # trigger persistence mechanism implicitly
> > > > >
> > > > > The second is to use the _p_changed attribute of the persistent
> object
> > > on
> > > > > which the primitive is set. This explcitly tells the persistence
> system
> > > to
> > > > > include the object on which it's set into the current transaction:
> > > > >
> > > > > def amethod(self):
> > > > > self.mydict = {}
> > > > > self.mydict['a'] = 1
> > > > > self._p_changed = 1 # trigger persistence mechanism manually
> > > > >
> > > > > Variations on this theme extend to list methods too (e.g.
> list.append,
> > > > > list.pop, etc.)
> > > > >
> > > > > "Custom" classes can certainly persist, they just need to mix in the
> > > > > "Persistence.Persistent" class as a base class.
> > > > >
> > > > > As long as you obey this (slightly annoying, but necessary) rule,
> you
> > > > > shouldn't need to use PersistentMapping (it's really just a
> convenient
> > > > > wrapper that does this "magic" for you) or make any other wrappers
> for
> > > other
> > > > > mutable objects.
> > > > >
> > > > > I don't know why you're using __setstate__, but ummmm.. I won't go
> > > there.
> > > > > :-) I didn't look at your product, but I don't think I need to to
> > > answer
> > > > > your question...
> > > > >
> > > > > > Hi I am trying to get a handle on how I should handle peristence
> in my
> > > > > > python products. I have read all the ZODB documents and all the
> > > Product
> > > > > > tutorials, which all led me to believe that 1) mutable objects
> such as
> > > > > > lists and dictionaries are not persistent and that updates to
> these
> > > will
> > > > > > not be implicitly saved into the ZODB, and 2) that custom classes
> > > would
> > > > > > certainly not persist. That all seemed fine, and I used persitent
> > > > > > mapping and __setstate__ to fill things back in where necessary.
> But
> > > > > > then I decided to demonstrate that persitence does break as
> suggested.
> > > > > >
> > > > > > I used boring product, added a dicitonary and a custom class that
> > > > > > contains it's own dictionary.... let the user update name : value
> > > pairs
> > > > > > for both, and print the contents through index.dtml
> > > > > >
> > > > > > The problem is that everything persists fine !!!! through
> restarts,
> > > > > > everything?
> > > > > >
> > > > > > Why does it work??? shouldn't it not?
> > > > > >
> > > > > > I have attached the modified boring product .... boringplus .....
> it's
> > > > > > dead simple to follow if you have made products before.
> > > > > >
> > > > > > Any explanation would be really nice.
> > > > > >
> > > > > > regards
> > > > > > Matt
> > > > > >
> > > > > >
> > > >
> > > >
> >
> >
> > _______________________________________________
> > Zope maillist - Zope@zope.org
> > http://lists.zope.org/mailman/listinfo/zope
> > ** No cross posts or HTML encoding! **
> > (Related lists -
> > http://lists.zope.org/mailman/listinfo/zope-announce
> > http://lists.zope.org/mailman/listinfo/zope-dev )
> >
> >
>
>
> _______________________________________________
> Zope maillist - Zope@zope.org
> http://lists.zope.org/mailman/listinfo/zope
> ** No cross posts or HTML encoding! **
> (Related lists -
> http://lists.zope.org/mailman/listinfo/zope-announce
> http://lists.zope.org/mailman/listinfo/zope-dev )
>