[Zope-dev] __getattr__ and Acquisition

Andreas Kostyrka andreas@kostyrka.priv.at
23 Sep 2002 17:00:36 +0200


Am Mon, 2002-09-23 um 10.35 schrieb Lennart Regebro:
> From: "Andreas Kostyrka" <andreas@kostyrka.priv.at>
> > Nope it is not. In a normal method you can access something acquired
> > like this:
> > self.acquired_value.
> 
> I often do just that. :-) I'm not 100% sure what you need to include for
> that to work, but I would expect that it is Aqcuisition.Implicit.
Well, Acquisition does not work in __getattr__. This seems trivially
because the "self" is unwrapped in the case of __getattr__, while it's
wrapped when called on a normal method.
> 
> > The problem is, that __getattr__ does not have access to the acquisition
> > chain.
> 
> Well, it does, but it typically causes infinite recursion if you aren't
Well, it would perhaps make sense for Acquisition to use the
equivalent of getattr(self.aq_explicit,name) instead of
getattr(aq_base(self),name)
This way you have no infinite recursion, but still can acquire things
explicitly with aq_acquire :)

> careful. Something like this might work (this is untested code, adapted from
> something that is a bit more complex that we are doing):
> 
>     def __getattr__(self, name, marker=None):
>         if not name.startswith('_') and not name.startswith('aq_'):
>             if not name in self._v_ignore_attrib:
>                 subob = getattr(self,name,_marker)
Well, where do you intenden your getattr to get the attribute from? 
>                     self._v_ignore_attrib=[]
>                     # Return it in context of self, forgetting
>                     # its location and acting as if it were located
>                     # in self.
>                     return aq_base(subob)
>                 else:
>                     self._v_ignore_attrib.append(name)
> 
>         raise AttributeError, name
> 
> 
> > Basically I want "Transparent Folders" which get their "transparent
> > values from the Acquisition path.
> 
> Aha. Well, I wouldn't call it trivial, but it is definitely doable.
Difficult. Because __getattr__ does not have access to the acquisition
chain. (Just looking at Acquisition.c makes my head go all jelly ;) )

1.) Change Acquisition to call getattr not on self but on an explicit
wrapper of self. see above. 
Problem: Compability with Zope? Should probably work. But perhaps there
are things that rely on self being the object and not an explicit
Wrapper.
Problem: The idea of patching Acquisition.c makes my head spin.
Problem: Not possible to fix it up as an Product -> needs a patch to
Zope.

2.) Fetch my a wrapped copy of self from the Python call stack.
Problem: It's an example of code that would be labelled "Do not copy
this style!"
Problem: Can break at the most curious moments.

3.) Store the wrapped self in some attribute during traversal.
Problem: This is plain wrong. It's not safe in a number of ways, ...
         (threads, multiple acquisition paths, etc.)

I've implemented solution 2) because 
- it's packable as a product
- I'm not sure a core change to Acquisition.c is something that has ANY
chance of getting into Zope.
- I'm not 100% sure that changing Acquisition.c will not break Zope in
some subtle ways.
- I'm already past the delivery deadline for my small application of
this. Hacking the Python stack seems something that I can predict much
better than any try to hack Acquisition.c :(

Andreas