[Zope] Subclassing from Custom Python Classes

Chris McDonough chrism@digicool.com
Wed, 24 May 2000 00:38:03 -0400


> >> You should also note that your subclass must obey the ZODB
> >> persistence rules, which basically state that mutable sub-objects
> >> should be treated immutably. For example,
> >>
> >> self.bird='parrot' # OK
> >> self.map['bird']='parrot' # NOT OK, will not trigger persistence
> >>                             machinery
> >> m=self.map
> >> m['bird']='parrot'
> >> self.map=m # OK, treats a mutable object immutably
> 
> What are these "persistence rules" and how come the second example is
> ok?  I thought in Python, when you assign "m = self.map" that m is
> simply pointing to the same object as self.map and that any changes to
> m affect self.map too?  Does the "self.map = m" have any effect?
> Don't they point to the same object?

It's a long story.  :-)  Attributes of Zope objects need to play by some
ground rules to be persistent.  The description in the docs is sort of a
half truth.  It works as described, but you can also do something like:

self.map['bird'] = 'parrot'
self._p_changed = 1

to trigger the persistence machinery.  The "m=self.map..." stuff in the
example does the same thing.  In either case you're bringing it to
Zope's attention that it needs to at some point re-write the object
referred to by "self" out to the ZODB.  By doing the jiggery up there
where you use "m" as a temp object, operate on it, and then reassign
"self.map" to "m" in order to let Zope know you've really changed the
object and that you really want to write a new copy of it out to the
ZODB when it's convenient for it to do so.  the _p_changed flag applies
to any Zope object, and just needs to be set true at some point during
the method to let the persistence machinery know that the object has
changed state.

In english the phrase "mutable sub-objects should be treated immutably"
means that attributes of the Zope object you're mucking with that can be
reassigned "in-place" (things you can append to like a list, or add
items to like a dictionary) should be treated as though they can't be.
So when saying (where 'self' is a Zope object):

self.mylist.append("foo")

This should be given special treatment, either by saying:

self.mylist.append("foo")
self._p_changed = 1
 
or

mytmp = self.mylist
mytmp.append("foo")
self.mylist = mytmp

> 
> I ask because I've already built my first product based on a custom
> python class I wrote (its a router object that has methods to query
> various snmp oids) based on a ZClass and I want to make sure that I am
> not doing anything wrong.
> In addition to the methods that query the oids, I store the results in
> an instance variable of my Python class so I can cache the information
> for a specified amount of time.  Is this safe to do?  Can I store
> these values in my Python instance (self.xxxx), not a ZClass property?

Sure, just make sure you abide by the stuff above.

> Also, What happens if multiple people activate my query method, do I
> need to worry about them stomping over each other as the method writes
> the results to the instance variables?  Is there any record locking of
> objects?

The ZODB will flag a ConflictError and will cause the second attempter
to retry.  This is pretty normal, and your data won't get munged.  Look
out, however, if you're really concerned, about "hot spots" that can
effect performance.
 
> Lastly, since I couldn't really find any pointers regarding a builtin
> Zope scheduler that is bug free, I need to write a small python script
> that I can place in a cron job to run every ten minutes to call the
> query methods of these objects so they update their cache instances.
> Is there a link on how to get a regular Python script access to the
> ZODB?

Yes... sort of.  Try looking for a HowTo named "The Debugger is Your
Friend" by Michel Pelletier.  That shows you how to use the Zope module
from inside python.  It's simpler than you might expect.  Here's an
example (make sure you shut down your Zope before you try this or it
won't work):

[chrism@opar chrism]$ cd Zope2.1.6/lib/python
[chrism@opar chrism]$ python
>>> import Zope
>>> app = Zope.app()
>>> app
<Application instance at 8455220>
>>> dir(app)
['Control_Panel', '__allow_groups__'........]

Play around inside Python, call methods on things, etc.  This is a great
way to learn more about Zope.