[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.
>
>hth,
>
>-Casey
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.
Thanks
Etienne
More information about the Zope
mailing list