[Zope-dev] improving the utility and adapter lookup APIs

Gary Poster gary.poster at gmail.com
Mon Nov 30 09:46:06 EST 2009

On Nov 30, 2009, at 4:05 AM, Brian Sutherland wrote:

> On Wed, Nov 25, 2009 at 10:17:41PM +0100, Hanno Schlichting wrote:
>> On Wed, Nov 25, 2009 at 9:52 PM, Tres Seaver <tseaver at palladion.com> wrote:
>>> Hmm, I may be missing something here, but if Foo implements IFoo, then
>>> the getAdapter lookup for it will short circuit, leading you into
>>> infinite recursion.  Except that it doesn't:
>> [snip example]
>>> which strikes me as wildly disjoint:  the IFoo behavior is "expected"
>>> (short-circuit the lookup if the object already provides the interface),
>>> while the getAdapter behavior is a puzzlement.
>> This has been mentioned numerous times as one of those odd and
>> unexpected differences between the IFoo vs. get/queryAdapter semantic.
>> IIRC the only use-case I ever heard of for the getAdapter semantic,
>> was the possibility to override the behavior promised by the interface
>> with a different adapter without touching the class that implements
>> the interface directly.
>> I think changing this falls into the category of: Small backwards
>> incompatibly that seem worthwhile to make the behavior consistent and
>> expected.
> I do agree that this behaviour is inconsistent with the common idea of
> adapters in the ZCA. So it doesn't have to be in the "main API" to the
> ZCA, i.e. the one people most heavily and frequently use.
> But, I'll argue that it should be still possible if you are willing to
> go outside the main API.
> My particular usecase is Location objects implementing IPublishTraverse
> without depending on the default traversal adapter:
>    class FakeContainerOfSomeKind(Location):
>        implements(IPublishTraverse)
>        def publishTraverse(self, request, name):
>            if name.isdigit() and do_i_contain(name):
>                return get_the_object_i_contain(name)
>            # fallback to default traversal adapter without depending on it
>            traverser = getMultiAdapter((self, request), IPublishTraverse)
>            return traverser.publishTraverse(request, name)
> I wouldn't know how to implement the above code without either depending
> directly on the default traversal adapter or making an
> IDefaultPublishTraverse marker interface. Neither of those, in my
> opinion, is as elegant as the above.

I'd argue what you have is pretty obscure though--that is, reading your code example, I'd have to stare at it a while to figure out why it works, and I know the component machinery pretty well.  The IDefaultPublishTraverse thing would be inelegant but much more readable.  I'd want to think about this class of use cases harder if it were regarded as an important one.  I am myself somewhat interested in being able to turn off the short-circuit behavior explicitly if desired.

That said, for "multiadapters" involving more than one required object, IMO the short-circuit behavior should never be invoked.  It is not clear that the first object is the one that should be checked for already providing the desired interface.  Therefore, in this particular usage, ``IPublishTraverse(self, request)`` would do what you want.


More information about the Zope-Dev mailing list