[Zope] reindex_object in __setattr__ method not working. (was: Losing acquisition wrapping between method calls)

Etienne Labuschagne elabuschagne at gmsonline.co.za
Fri Feb 6 04:04:19 EST 2004

At 12:34 PM 5/2/2004 -0500, Casey Duncan wrote:
>On Thu, 05 Feb 2004 09:59:39 +0200
>Etienne Labuschagne <elabuschagne at gmsonline.co.za> wrote:
> > Hi there,
> >
> > I am using __setattr__ in my class to decide if the class needs to be
> > reindexed or not.  The problem is, the moment you enter the
> > __setattr__ method, self is not acquisition wrapped anymore, which
> > means that reindex_object does not work since it cannot acquire the
> > Catalog.
> >
> > This can be illustrated with the following small test class:
> >
> > class AQTest(CatalogAware, SimpleItem):
> >      '''Test class'''
> >      meta_type = "Health Window Test"
> >
> >      def __setattr__(self, attrName, attrValue):
> >          if attrName.startswith('abc'):
> >              self.reindex_object()  #This doesn't work, since self is
> >              no
> > longer acquisition wrapped here, eg. self.aq_parent raises an error
> >          self.__dict__[attrName] = attrValue
> >
> >      def test(self):
> >          '''Test method'''
> >          self.abcname = 'John'
> >
> >
> > Any suggestions on how to fix this?
>I think you have found that __setattr__ is too low-level for this to
>work. Many operations may do setattr without your knowing it also (like
>ZODB), so indexing there although attractive for automation purposes is
>not going to work in practice.
>The canonical, if less automated, way it is done is to have mutator
>methods change attributes and call reindex object at the end. If you
>want to, you could just have a single mutator method which lets you set
>any attributes. In fact this would be more efficent then reindexing on
>every attribute change. Plus you can protect it with permissions so it
>can be called from untrusted code::
>   def set(self, **kw):
>       """Set attrbiutes and reindex"""
>       for name, value in kw.items():
>           setattr(self, name, value)
>       self.reindex_object()
>OTOH, this method doesn't give much guidance as to which attributes to
>set. In general it is considered bad practice to manipulate attributes
>of objects directly and informally. You could improve this without
>loosing generality however::
>   def set(self, **kw):
>       """Set attrbiutes and reindex"""
>       for name, value in kw.items():
>           getattr(self, name) # Assert the attribute exists
>           setattr(self, name, value)
>       self.reindex_object()
>Ultimately, this is probably best though::
>   def edit(self, foo=None, bar=None, baz=None):
>      if foo is not None:
>          self._foo = foo
>     ...
>     self.reindex_object()
>That makes it clear what is editable from the signature and breaks if
>you typo a name.

Thanks for clarifying the __setattr__ behaviour (also pointed out in 
another thread to me by Dieter Maurer),

Usually I always make use of getters and setters (which would usually be 
the mutators) and never make use of direct attribute access (the example 
above was very brief and gave the impression of direct attribute access).

After being spoilt by new-style properties, I tried to implement properties 
using getters and setters as new style classes is not yet an option in ZODB 
3.2.  My scheme worked perfectly and gives on the syntaxical ease of use 
that direct attribute access gives one, but with the correctness of getters 
and setters.  Unfortunately I ran into this one small issue that is 
seemingly unfixable.  This now leaves me with two choices - drop the 
"properties" or drop the automatic indexing.  Due to the nature of my 
current product's architecture, the latter will be dropped and I will 
trigger reindexing "manually".

I am currently trying to get ZODB 3.3a to work with Zope 2.7 so that I have 
access to new-style classes.  This will give me the best of both worlds and 
I'll have to drop nothing.


More information about the Zope mailing list