[Zope-CMF] __setattr__ in a persistent class

Gregoire Weber gregweb@gmx.ch
Wed, 30 Jul 2003 01:55:15 +0200


Hi all!

Q: Somebody on the list, knowing how to intercept attribute=20
   setting and getting with __setattr__ and __getattr__ in=20
   a persistent subclass?

What I like to do:

   I created a CMF content type named TransBag (a (semi)=20
   transparent bag holding another content object) that=20
   should hold other content object.=20

   This should allow selective access (read and write) to=20
   attributes of the content object (like title, description,=20
   etc) and to the bag (like portal_type, workflow_history).

   This selective access should be totally transparent for=20
   existing CMF tools like portal_metadata etc.

   I need this concept for the next versions of CMFCollection.

Some background about my investigations:

   I searched all possible zope mailing list archives. Some=20
   messages said, that it is extremly hard to do that (years=20
   1999 and 2000 as I remember), others said that it is=20
   possible to do that in some manner (from Zope 2.2 on, but=20
   without info about how to do it). There were messages=20
   stating that I should trigger the persistence mechanism=20
   by setting self._p_changed =3D 1.

   Unfortunately this doesn't seem to work fro persistent=20
   objects.

   I've stepped through the code with the pdb and recognized=20
   that setting self._p_changed =3D 1 doesn't help. It seems=20
   that self._p_changed is some kind of write protected.=20
   Resulting in 0 (zero) after the write!

   So writing is not persistent! arrrgh!

   I'm totally stuck. I'm not a low level ZODB guru.

Can somebody point me in the right direction?=20
Alternative concepts to achieve the above goal?

Help and pointers would be apreciated! Thanks.

Sorry for the long e-mail. Below a simplified code snippet.

Gregoire

-------------------------------------------------------------
class TransBag(PortalContent, DefaultDublinCoreImpl):
    """Transparent Bag

    **simplified code version**

    Holds any arbitrary cmf content object. Allows attribute=20
    specific read and write access policies.
    """

    def __init__(self):
        self.__dict__['_attrs'] =3D {}
        # other stuff

    def __setattr__(self, name, value):
        """Intercept attribute setting.
        """
        if self._isDirectAccessAllowed(name): # '_blah' etc.
            # set attribute to TransBag object
            self.__dict__[name] =3D value
        else:
            # set attribute to '_attrs' dictionary to be able=20
            # to intercept attribute reading with '__getattr__'
            self.__dict__['_attrs'][name] =3D value
            self._p_changed =3D 1=20
            # also tried self.__dict__['_p_changed'] =3D 1
            # --- reading _p_changed in pdb results in 0 ---

            ### tried also this: didn't work neither!
            #attrs =3D self._attrs
            #attrs[name] =3D value
            #self.__dict__['_attrs'] =3D attrs

    def __getattr__(self, name):
        """Intercept attribute getting.

        Called if attribute does not exist on the object
        (because intercepted in __setattr__ or aquired)
        """
        if name in self._attrs.keys():
            return self._attrs[name]
       =20
        # without this aquisition would not work
        raise AttributeError

    # etc.
_____________________________________
Gr=E9goire Weber
mailto:gregoire.weber@switzerland.org