[Grok-dev] How I Will Have Broken Grok

Brandon Craig Rhodes brandon at rhodesmill.org
Wed Sep 19 16:36:25 EDT 2007

I have just checked in a change to "zope.traverser" that will destroy
Grok when it gets released, but, by a happy coincidence, I just ran
across this fact by accident while chasing down another question I had
about the Grok source code. :-)

My change improves the AbsoluteURL adapter, which - as I have already
described on this list - failed to adapt its context to ILocation
before accessing "__name__" and "__parent__".  My change fixes this.

But my recent change also removes the extraneous "_getContextName"
method on "AbsoluteURL", because:

  (a) That method was used by "AbsoluteURL.__str__" but not by
      "AbsoluteURL.breadcrumbs", whereas the two functions were
      clearly intended to work the same.

  (b) It does something perfectly obvious for "__name__" that's done
      in-line already in the code that grabs "__parent__".

  (c) It is mentioned nowhere else in the Zope 3 code base.

  (d) To be correct as a stand-alone call, "_getContextName" would
      also have to adapt its context to ILocation, which would have
      meant two adaption calls per call to "AbsoluteURL.__str__".

  (e) Most importantly: because no tests failed because of its
      removal. ;-)

So you can imagine my surprise when I ran across the following code in

class GrokViewAbsoluteURL(AbsoluteURL):

    def _getContextName(self, context):
        return getattr(context, '__view_name__', None)
    # XXX breadcrumbs method on AbsoluteURL breaks as it does not use
    # _getContextName to get to the name of the view. What does breadcrumbs do?

So I was not the only one wondering why "breadcrumbs" worked
differently. :-)

So, I had to ask: what on earth is this "GrokViewAbsoluteURL"?

Well, it turns out that it's a way to work around the fact that
AbsoluteURL was not properly coded. :-) In "grok/configure.zcml", we
find the comment:

  <!-- we register special IAbsoluteURL views on grok views so that
       can have them inspect __view_name__ instead of __name__.  
       __name__ is already used as the class name, and overriding it
       may make error messages more confusing.  -->

With AbsoluteURL now adapting properly, of course, I think the
solution becomes much simpler; we need to remove "GrokViewAbsoluteURL"
and in its place add something sleek like (but maybe with true ZCML in
place of the "grok" functions I'm using for the sake of example?):

class GrokViewLocation(object):

    def __init__(self, context):
        self.__name__ = context.__view_name__
        self.__parent__ = context.__parent__


 - Now that I know what it was for, I conclude that I was entirely
   correct to remove "_getContextName" from AbsoluteURL.  It was an
   unfortunate example of encouraging old-fashioned inheritance as a
   way to monkey around a problem that should have been solved cleanly
   with an adapter.

 - Whoever added the above class to Grok should probably have added a
   test case to Zope so that "_getContextName" would keep working.

 - I need some help, because this is very deep water, package-release-
   wise!  How do we coordinate having "grok" and "zope.traversing"
   change at exactly the same time so that they continue working for

   I suppose that we may need to put the terrible "_getContextName"
   back in place in "zope.traversing" for a few weeks, to give us time
   to calmly move Grok from using "GrokViewAbsoluteURL" to using
   something like my suggested "GrokViewLocation" above, and then
   finally release a version of "zope.traversing" that removes
   "_getContextName" once things look safe.

   Let me know.  This is my first experience with a product released
   as so many pieces. :-)

Brandon Craig Rhodes   brandon at rhodesmill.org   http://rhodesmill.org/brandon

More information about the Grok-dev mailing list