[Zope] Acquisition question
Brian Lloyd
Brian@digicool.com
Thu, 11 Feb 1999 22:32:14 -0500
> Hi,
>
> Can anybody explain why my dynamically created attributes
> can't find their acquired attributes up the hierarchy?
>
> I have the following code:
>
> class AcquTest(Acquisition.Implicit):
> "the implicitluy aquired one"
> __roles__ = None
> def __init__(self,color=None):
> if color:
> self.color = color
> def __getitem__(self,attr):
> if self.__class__.__dict__.has_key(attr):
> return self.__class__.__dict__[attr]
> if self.__dict__.has_key(attr):
> return self.__dict__[attr]
> try:
> return self.aq_acquire(attr)
> except:
> self.__dict__[attr] = AcquTest(attr)
> return self.__dict__[attr]
> local_html = HTML("<html>Local <!--#var color--></html>")
> index_html = HTML("""
> <!--#var page_header-->
> <!--#var color--><br>
> <!--#var page_footer-->""")
>
> aq = AcquTest('orange')
> aq.page_header = HTML('<html><font color="<!--#var color-->"
> size=+3><b>')
> aq.page_footer = '</font></html>'
> aq.name = 'AQ root object'
>
> aq.a = AcquTest()
> aq.a.b = AcquTest('blue')
> aq.a.color= 'green'
> ---8<------8<------8<------8<------8<------8<------8<---
>
> and when I access it through web as /aq , /aq/a or /aq/a/b
> it works as expected (prints orange, green and blue in
> respective coluor)
>
> but when i want to access a new attribute (retrieved from
> a database by attr in my real application), then it can't
> acquire the other attributes up the hierarchy.
>
> ie /aq/black does _not_ print black, instead it produces a traceback:
> ...
> KeyError: page_header
>
> So obviously acquisition is not working for me here ;(
This is because you have effectively defeated acquistion inside
your __getitem__ method. One of the best things about acquisition
is that it is so black box that you almost never have to think
about it - which makes it easy to forget that if you override
__getitem__ you may need to manually maintain the acquisition
chain.
Acquiring objects are actually "wrappers" which wrap an object with
its parent in a given context. This wrapping process is usually done
for you by the Acquisition machinery which is hooked to the c equivalent
of __getattr__. Anytime you get an instance attribute in a way that
bypasses
that getattr hook, you need to wrap the object yourself to maintain the
acquisition chain, using the __of__ method).
Here is a modified __getitem__ that should work:
def __getitem__(self,attr):
# Anytime we get an attr from an __dict__ directly
# rather than from a getattr, we need to wrap it
# before returning it
if self.__class__.__dict__.has_key(attr):
return self.__class__.__dict__[attr].__of__(self)
if self.__dict__.has_key(attr):
return self.__dict__[attr].__of__(self)
try:
# If we are able to acquire the attr directly via
# aq_acquire, we _dont_ need to wrap it - the
# aq_acquire method will have taken care of that
# for us...
return self.aq_acquire(attr)
except:
self.__dict__[attr] = AcquTest(attr)
return self.__dict__[attr].__of__(self)
Hope this helps!
Brian Lloyd brian@digicool.com
Software Engineer 540.371.6909
Digital Creations http://www.digicool.com