I'm trying to write a pretty transparent wrapper product in python, which will have one property, source_path, which contains a (string) path to another object. I can resolve this path to the object, no problem; but I cant' see how to delegate attribute requests to it. my __getattr__ fails with (snip - complete traceback later): File "/zope/Zope_software_home/lib/python/OFS/Traversable.py", line 95, in unrestrictedTraverse self=self.getPhysicalRoot() TypeError: object of type 'string' is not callable Which is weird, because I can do getPhysicalRoot() on both the wrapper and the wrapped object and it ain't a string.... Before I go further I'll explain the motivating scenario. We have four zope sites (on one server) which have a fair amount of content overlap. This content is not in a consistent location across sites (e.g. we might have www.site1/blah/bleh/foo and www.site2/blarf/foo). We have a non-technically-minded, overworked content manager and an ever-expanding mountain of content. Currently, her job is nearly impossible and i'm charged with creating the solution. So I thought I would: 1) build a single cmf site for content management (cmf also provides other things we need, so it seems to be a good fit). 2) customize workflow so that one stage of publishing consists of specifying where you want the content to appear, and then wrapper objects are created which will render the content in context *and* provide access to the wrapped object's properties. e.g. you'd get a form in which you can type in some variant of "site1/blah/bleh/foo" and "www.site2/blarf/foo", and we'd automagically create wrappers at those locations which point back to this content. 3) customize the management skins so that deleting or moving the source content also updates the wrappers. (sounds like zope 3 will make this easier, but who knows when that will be.) Alternative solutions to the above scenario would be welcome, but in the meantime, here's what I'm trying now for the wrapper product: # ... management methods snipped, they're working fine def get_source_object(self): """ return the (aq-wrapped) object referred to by source_path. """ obj = self.unrestrictedTraverse(self.source_path, default=None) return obj.__of__(self) # everything else comes from the source object. def __getattr__(self, name): obj = self.get_source_object() attr = getattr(obj, name) # do I need to aq-wrap attr if obj is aq-wrapped? not sure. return attr.__of__(self) # return attr doesn't work either Now I go into zope and create one of these at /paul_stuff/, called "whatever", and point it to '/index_html'. That seems to work. Now let's have a look, at the prompt...
wrapper = app.paul_stuff.whatever wrapper <ContentProxy instance at 8c9d418> wrapper.source_path '/index_html' obj = wrapper.get_source_object() obj <DTMLMethod instance at 8a95ca0> obj.getPhysicalPath() ('', 'index_html')
So far so good... but try to access something in obj via wrapper, and it's no good.
obj.raw '<dtml-var standard_html_header>\n<dtml-var zope_quick_start>\n<dtml-var standard_html_footer>' wrapper.raw Traceback (most recent call last): File "<stdin>", line 1, in ? File "/zope/InstanceHome/Products/ContentProxy/ContentProxy.py", line 68, in __getattr__ obj = self.get_source_object() File "/zope/InstanceHome/Products/ContentProxy/ContentProxy.py", line 63, in get_source_object obj = self.unrestrictedTraverse(self.source_path, default=None) File "/zope/Zope_software_home/lib/python/OFS/Traversable.py", line 95, in unrestrictedTraverse self=self.getPhysicalRoot() TypeError: object of type 'string' is not callable
This is baffling. Where am I calling a string?? I've been searching for similar issues on google and turning up nothing that helps... this message seems to indicate that overriding __getattr__ should be doable: http://zope.nipltd.com/public/lists/dev-archive.nsf/b1b1e2c766c8f6c7802568c1... -- Paul Winkler "Welcome to Muppet Labs, where the future is made - today!"
Update for anyone interested... if there were explorer's maps for zope product hackers, it would say "here be dragons" where __getattr__ and __bobo_traverse__ are. Not for the faint of heart. actually __bobo_traverse__ seems pretty sensible as long as you don't get too ambitious :) I spent some time fiddling with __getattr__ as described previously, then following advice from SteveA on #zope I switched to overriding __bobo_traverse__. that was equally confusing - it worked ok with wrapping DTML *sometimes* (but not for /index_html for some reason), but didn't work with zpt and I couldn't figure why. spent much time in #zope trying to figure it out - eventually someone (zopezen?) said "another sacrifice at the altar of the mythical symlink product" and I threw in the towel. somebody else said "there's a reason the mythical symlink product is mythical." :-\ There were also hints that this kind of thing might be easier in zope3. Instead I'm going to programatically copy and paste my shared content to its destinations as part of my workflow. there will still be some ugly issues with getting it to fit in properly in all the contexts I need to handle, but I don't think it could possibly get as weird as working with __getattr__ and __bobo_traverse__. On Wed, Oct 09, 2002 at 05:33:04PM -0700, Paul Winkler wrote:
I'm trying to write a pretty transparent wrapper product in python, which will have one property, source_path, which contains a (string) path to another object. I can resolve this path to the object, no problem; but I cant' see how to delegate attribute requests to it. my __getattr__ fails with (snip - complete traceback later): (snip)
-- Paul Winkler "Welcome to Muppet Labs, where the future is made - today!"
participants (1)
-
Paul Winkler