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