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

Shane Hathaway shane at hathawaymix.org
Thu Nov 26 05:53:39 EST 2009


Martijn Faassen wrote:
> But someone needs to think of a feasible upgrade scenario. We could 
> instrument all calls to IFoo and see whether a default argument is in 
> use, but what then? I'd be hard to distinguish a default argument from 
> one we're meant to adapt. I'd also be non-trivial to scan code.

Here is an interface decorator I intend to try out soon.  It adds 
convenient component lookup methods to a particular interface without 
requiring any changes to zope.interface.

--- (snip) ---

from zope.interface.interfaces import IInterface
from zope.component import getAdapter
from zope.component import getMultiAdapter
from zope.component import getUtility
from zope.component import queryAdapter
from zope.component import queryMultiAdapter
from zope.component import queryUtility

def componentlookup(iface):
     """Decorator: adds zope.component lookup methods to an interface.

     Adds utility([default], [name]) and adapt(*args, [default], [name]).
     """
     assert IInterface.providedBy(iface)

     def utility(**kw):
         if 'default' in kw:
             return queryUtility(iface, **kw)
         else:
             return getUtility(iface, **kw)
     iface.utility = utility

     def adapt(*args, **kw):
         if len(args) == 1:
             # simple adapter lookup
             arg = args[0]
             if not 'name' in kw and iface.providedBy(arg):
                 # The object passed in already provides this interface,
                 # and no adapter name was provided, so return the object
                 # unchanged.
                 return arg
             if 'default' in kw:
                 return queryAdapter(arg, iface, **kw)
             else:
                 return getAdapter(arg, iface, **kw)

         # multi-adapter lookup
         if 'default' in kw:
             return queryMultiAdapter(args, iface, **kw)
         else:
             return getMultiAdapter(args, iface, **kw)
     iface.adapt = adapt

     return iface


--- (snip) ---

Example usage:

     @componentlookup
     class IFoo(Interface):
         pass

     class Foo(object):
         implements(IFoo)

     IFoo.adapt(Foo())
     IFoo.adapt(Foo(), HTTPRequest(), name='edit')
     IFoo.adapt(Foo(), name='x')
     IFoo.adapt(Foo(), default=None)
     IFoo.utility(default=None)

I think class decorators were added in Python 2.6, but in earlier 
Pythons you can do this instead:

     class IFoo(Interface):
         pass
     componentlookup(IFoo)

Shane


More information about the Zope-Dev mailing list