[Zope3-dev] IMPORTANT: How to look up adapters

Jim Fulton jim at zope.com
Fri Jul 2 11:42:24 EDT 2004


For simple adaptation, where you adapt a single object to a single
interface without a name providing qualification, you should call the
interface:

   adapter = iface(ob)

If you want to provide a default to be used if the adapter
can't be found, just pass it as an additional argument:

   adapter = iface(ob, default)

Note that if the object already provides the interface, then
the object is returned.  Otherwise, if the object conforms
to the interface (has a __conform__ that returns a non-None
value for the interface), then the __conform__ method will
be used to create the adapter.

This syntax has only been around for a couple of months.
It appears that a number of people haven't heard about it,
as I've recently noticed new code using the old syntax:

   adapter = getAdapter(ob, iface)

We have a problem with the old syntax.

We used to have four functions, getAdapter, queryAdapter,
getNamedAdapter, queryNamedAdapter. The "Named" methods had
different sematics than the non-"Named" methods.  The non-
"Named" methods would return the object if the object already
provided the interface. They would also return the result of
calling the __conform__ method on the object, if present and if
it's result was not None. The "Named" methods didn't consider
whether the object aleady provided or conformed to the interface.
The rational for this was that the name in a named-adapter
lookup is an interface qualifier.  An object cannot provide
or conform to a qualified interface.  A qualifid interface
can only be provided through adapter lookup.

Now it happens that the un-"Named" methods allowed a name argument
to be provided. This was for backward compatability and lasted
much longer than it should have. They generated deprecation warnings
if non-empty names were provided.

In an attempt to simplify the API just before the beta, the "Named"
and un-"Named" methods were incorrectly merged.  This was based on the
observation that they both seemed to take the same arguments.  I
wasn't paying close enough attention and OKed this. :(  This led
to the following problem.  With the current remaining
queryAdapter and getAdapter functions, the name argument is ignored if
the object provides or conforms to the interface.  This is a latent
bug that hasn't bitten us yet, AFAIK, because we aren't making very heavy
use of named adapters yet.  This will be more of a problem in the future.

There are two ways I can fix this:

1. I can add back the "Named" methods and remove the name argument
    from the un-"Named" methods.

2. I can give the current un-"Named" methods the semantics of the
    old "Named" methods.  This means that queryAdapter and getAdapter
    will no longer consider whether an object provides or conforms to an
    interface.

    We don't really need to call getAdapter or queryAdapter to
    get the old behavior, because we can just call the interfaces.
    Being able to get a simple adapter either by calling get/queryAdapter
    or by calling the interface violates Python's "one way to do it"
    philosophy.

    There is one case where calling an interface isn't equivalent to
    get/queryAdapter.  If you want to supply a context argument to specify
    a different place to look up adapters, you can't pass it to the interface.
    This is an extreme edge case. I know of no place in the Zope 3 tree where
    this is needed, but it is something we want to allow.  I propose to
    provide new functions: getSpecialAdapter and querySpecialAdapter.  These
    functions will require a context to be specified and will return the object
    if it provides the requested interface and will use __conform__ if it
    conforms to the interface.

Both of these options are backward inconpatible.  While I'm not happy about
doing this after the beta, it's better than doing it after the final release.

I prefer option 2 because:

- It provides a single way to do simple adaptation

- It provides simpler names for named-adapter lookup, which
   are more consistent with multi-adapter (also named) lookup.

- It requires the least code change.

It's unclear which option is the least impact on add-on
software.  I don't know how many people are still doing
simple-adapter lookup with getAdapter and queryAdapter.
With the change, these calls will break, because the name
argument will be required.  On the one hand, breakage is bad,
but, the breakage should be obvious.

I'm going to go ahead and do this (ootion 2).  Perhaps I'll
change my mind if there are loud objections, but I hope there
won't be. :)

Jim

-- 
Jim Fulton           mailto:jim at zope.com       Python Powered!
CTO                  (540) 361-1714            http://www.python.org
Zope Corporation     http://www.zope.com       http://www.zope.org


More information about the Zope3-dev mailing list