[Zope3-dev] zodb __parent__ and weakref
Shaun Cutts
shaun at cuttshome.net
Fri Feb 24 22:58:25 EST 2006
Opps,
The code I said would be attached...
> -----Original Message-----
> From: zope3-dev-bounces+shaun=cuttshome.net at zope.org
[mailto:zope3-dev-
> bounces+shaun=cuttshome.net at zope.org] On Behalf Of Shaun Cutts
> Sent: Friday, February 24, 2006 10:18 PM
> To: 'Chris Withers'; shaunc at speakeasy.net; 'zope3-dev'
> Subject: RE: [Zope3-dev] zodb __parent__ and weakref
>
> Chris,
>
> > You need to get into the habbit of CC'ing in the list you're
replying
> > too...
>
> Sorry -- I was thinking that, if this was not a problem w/ ZODB and
> external objects, but I've missed something in implementation, maybe I
> should have been communicating on Zope3-users instead. Now I don't
know
> if I've communicated clearly enough to conclude this yet.
>
> > shaunc at speakeasy.net wrote:
> > > The data is in Postgres, but I already have a python data
> > marshalling/demarshalling/business logic used by other processes, so
I
> > want to use this interface with ZOPE as well.
> >
> > Okay, and what is this interface?
>
> Do you want to see the *whole* interface ? :) I would think it would
> suffice to say: it has interfaces to query the database and return
> python objects constructed from the data, and various "business logic"
> interfaces that trigger creation of new data in the database.
>
> Zope is only one client. Others will be interacting with the database.
>
> > > Should I be trying to inherit from Persistent rather than
> __getstate__,
> > __setstate__? ... perhaps there is a way as flagging a member
> volatile?...
> > Or that I want to control refresh myself?
> >
> > I don't see what implementing IContainer has to do with Persistent,
> > __getstate__ or __setstate__... or am I missing something?
> >
> I'm only implementing a prototype now, but in production, the database
> will have >=30 million objects in it after 2 years of use. For this
> reason, and because the db will be changing outside, it doesn't seem
> sensible to store the db objects in ZODB. This was also the opinion in
> zope3-users when I asked about this earlier.
>
> Instead I want to have a container which queries the database for data
> itself, but avoids having these objects be put in the zodb, even if it
> itself is in the zodb.
>
> You are saying that it isn't a good approach to implement __getstate__
> and __setstate__... but I don't see why this should be so? Can anyone
> explain why they are called so often? It seemed from other threads
that
> the danger would rather be that your data doesn't get stored at all if
> you don't explicitly set _p_changed (or whatever its called)....
>
> I've attached a version of my attempted implementation (cleaned up
from
> the post in <[Zope3-Users] newbie design questions for UI to external
> data>.
>
>
> > > I thought that overriding __getstate__ and __setstate__ simply
> overrides
> > pythons default versions of these, which would be called just as
often
> as
> > my versions. I guess perhaps the default versions are especially
> efficient
> > because they just pass the instance dictionary back and forth(? --
but
> > then what does ZODB do with the instance dictionary? Why does it ask
> for
> > it if the object itself is ok?)
> >
> > Don't worry about any of these things, just don't try and implement
> > anything funky, you don't need to and you're likely to get hurt, as
> > you've found...
> >
> How should I implement this differently, or what bad assumptions am I
> making? To my mind, __getstate__ and __setstate__ are the normal way
to
> control persistence in pickle-using python, so "funky" is in the eye
of
> the beholder.
>
> - Shaun
>
>
>
> > Chris
> >
> > --
> > Simplistix - Content Management, Zope & Python Consulting
> > - http://www.simplistix.co.uk
> >
>
>
>
> _______________________________________________
> Zope3-dev mailing list
> Zope3-dev at zope.org
> Unsub: http://mail.zope.org/mailman/options/zope3-
> dev/shaun%40cuttshome.net
>
-------------- next part --------------
class HollowContainer( IterableUserDict, Contained ):
"""
Implements L{IHollowContainer}
Strategy: for add and delete, notify the database directly; for
update of contained object, however, we want to listen for
ObjectModifiedEvent. This is better than getting a notification
from the objects, as an edit form may set several fields, and then
send the notification when done; so the event can be treated as a "commit"
Keys: _iserial is key to objects in dictionary
>>> from zope.interface.verify import verifyClass
>>> verifyClass( IHollowContainer, HollowContainer )
True
"""
implements( IHollowContainer, INameChooser )
# defaults for IHollowContainer
database = None
containedInterface = None
# defaults for ILocation (base of IHollowContainer)
__parent__ = None
__name__ = None
def __init__( self ):
super( HollowContainer, self ).__init__( )
self.__setstate__()
def __setitem__( self, key, obj ):
"Implements L{cranedata.web.interfaces.IFundContainer.__setitem__}."
if key in self.data:
raise DuplicationError( "key %s already present" )
self.add( obj )
def add( self, obj ):
obj = self.containedInterface( obj )
object.__setattr__( obj, '__parent__', self )
object.__setattr__( obj, '__name__', self.getKey() )
setitem( self, self.data.__setitem__, self.getKey(), obj )
self.database.add( obj )
self.incrementKey()
def __delitem__( self, key ):
obj = self.data[ key ]
self.database.delete( obj )
del self.data[ key ]
uncontained( obj, self, obj.__name__ )
# ok -- deal with update events:
def update( self, obj ):
assert obj.__parent__ == self
self.database.update( obj )
# support ZODB persistence:
# __getstate__, __setstate__ need to save info stored
# at object about its context, but should look "hollow"
# from the point of view of the DB
def __getstate__( self ):
# we have to remember our tree-location
dct = {
'__name__' : self.__name__,
'__parent__':self.__parent__
}
if hasattr( self, '__annotations__' ):
dct[ '__annotations__' ] = self.__annotations__
return dct
def __setstate__( self, dct = None ):
if dct:
self.__parent__ = dct[ '__parent__' ]
self.__name__ = dct[ '__name__' ]
if '__annotations__' in dct:
self.__annotations__ = dct[ '__annotations__' ]
self.data = {}
self.database.connect()
self._load()
def _load( self ):
self.resetKey()
hollowDispatcher.register( self )
for row in self.database:
self.data[ self.getKey() ] = row
object.__setattr__( row, '__parent__', self )
object.__setattr__( row, '__name__', self.getKey() )
directlyProvides( row, IContained )
self.incrementKey()
def __del__( self ):
hollowDispatcher.deregister( self )
def getKey( self ):
return unicode( self._iserial )
def incrementKey( self ):
self._iserial += 1L
def resetKey( self ):
self._iserial = 0L
def checkName( self, name, object ):
return type(name) == long
def chooseName( self, name, object ):
return self.getKey()
class HollowDispatcher:
"""a single instance of this class is used to catch
event notifications for hollow containers.
"""
def __init__( self ):
self.registry = []
def register( self, container ):
if container not in self.registry:
self.registry.append( container )
def deregister( self, container ):
self.registry.remove( container )
def __call__( self, event ):
try:
parent = event.object.__parent__
except AttributeError:
return
for container in self.registry:
if parent is container:
container.update( event.object )
hollowDispatcher = HollowDispatcher()
More information about the Zope3-dev
mailing list