[Zope] help with __bobo_traverse__

Karl Anderson kra at monkey.org
Thu May 27 18:45:22 EDT 2004

Mohamed Lrhazi <mohamed at your-site.com> writes:

> --On Thursday, May 27, 2004 9:15 PM +0100 Matt Hamilton 
> <matth at netsight.co.uk> wrote:
> > My initial thought is that maybe there is no context wrapper for
> > viewDomain when you return it.  I can't remember if it is added
> > automaticcally or not.  You could try:
> >
> > return getattr(self, 'viewDomain').__of__(self)
> >
> > and see if that works.
> >
> I will try that....
> > Having said that, taking another look at your code, I think it works as
> > expected.  The first call to __bobo_traverse__ gets 'foobar', but how
> > does foobar get '1'?  Does an object called '1' exist anywhere?
> I said I was a newbie, didn't I? :)
> In <>
> There is no object "foobar" nor "1" nor "2" ....
> yspanel is an instance of My product though. and I am trying to figure out 
> how to use __bobo_traverse__  to call a method to handle the above request, 
> where everything, from foobar and on, is parameters or commands...

I do this in two toy products, BlogFace and BlogTopic.


BlogFace uses __bobo_traverse__.  If name actually exists, return it
for publishing.  If name is an int, add something to the REQUEST and
return self.  If name is in a parameter dict, add something to REQUEST
and return self.  If no actual subobjects get in the way, we end up at
self's index_html, which does something with these stored agruments.

    def __bobo_traverse__(self, REQUEST, name):
        Consume trailing URL path and turn into arguments so long as
        they are convertable to ints.  Otherwise, traverse normally with
        collected arguments.  Note that this shadows subobjects with IDs
        that are convertable to ints.
        if re.match('^[0-9]+$', name):
            if not REQUEST.has_key('traverse_date'):
                REQUEST['traverse_date'] = []
        elif name in self.traverseParamOpts.keys():
            if not REQUEST.has_key('traverse_params'):
                REQUEST['traverse_params'] = []
            # normal traverse.  This can raise an AttributeError.  What can
            # we raise to get the publisher to do what it does in other
            # cases, besides making and raising a notFoundError ourselves?
            return getattr(self, name)
        return self

BlogTopic does this more efficiently by munging the traversal stack in
__before_publishing_traverse__, so that all of those traversal calls
are short-circuited.

    # should be using the tools in BeforeTraverse.py?
    def __before_publishing_traverse__(self, obj, req):
        If the traversal stack is all intable strings that don't lead to
        attrs or items, put the date represented in the request and lop the
        stack, causing the publisher to call us for the next publishing step.
        stack = req['TraversalRequestNameStack']
        # do nothing unless we have only intable strs to traverse overall
        # XXX use something faster than re.match(str)?
        if stack and (len(filter(lambda x: re.match('^[0-9]+$', x), stack)) !=
        # Do nothing if there's an attr or item to publish, allows
        # things like custom views for dates. 
        # This isn't rigorous, there could still be something to publish,
        # but there isn't a mechanism to find any name that
        # BaseRequest.traverse would publish, other than copying the code.
        if stack:
            self_base = aq_base(self)
            if hasattr(self_base, stack[0]):
                dummy = self_base[stack[0]]
        # stop looking for next obj to publish by emptying stack
        req['TraversalRequestNameStack'] = []
            req['BlogTopicDate'] = seqToDate(stack)
            req['TraversalRequestNameStack'] = [self.dateErrorSkin]

Munging the traversal stack can have weird consequences for things
like breadcrumbs.

Karl Anderson      kra at monkey.org           http://monkey.org/~kra/

More information about the Zope mailing list