[BlueBream] Chaining Adaptors

Michael Howitz mh at gocept.com
Thu Jul 8 02:19:26 EDT 2010


Am 07.07.2010 um 13:27 schrieb Mike Rhodes:
> Hi,
> 
> I've a question about whether the ZCA will chain adapters when trying to 
> adapt from one type to another. I couldn't see a specific Zope Toolkit 
> mailing list, so if this is the wrong list please feel free to berate me 
> and point me toward the correct one!
> 
> The easiest way to explain my question is probably with some code.
> 
> Essentially what I am trying to do is to work out whether the ZCA can 
> "chain" adapters together when required to satisfy an adaptation 
> request.

No, this is currently not possible.

> In my example, you need to chain together two adapters: A->B 
> then B->C.

> ==========================
> 
> from zope.interface import Interface, implements
> from zope.component import adapts, getGlobalSiteManager
> 
> # I have three interfaces:
> class IInterfaceA(Interface):
>     pass
> class IInterfaceB(Interface):
>     pass
> class IInterfaceC(Interface):
>     pass
> 
> # Two adaptors between these interfaces:
> class AdaptorAB(object):
>     adapts(IInterfaceA)
>     implements(IInterfaceB)
> 
>     def __init__(self, adaptee):
>         pass
> 
> class AdaptorBC(object):
>     adapts(IInterfaceB)
>     implements(IInterfaceC)
> 
>     def __init__(self, adaptee):
>         pass
> 
> # And finally, a class implementing IInterfaceA
> class ClassA(object):
>     implements(IInterfaceA)
> 
> # Register my adapters
> gsm = getGlobalSiteManager()
> gsm.registerAdapter(AdaptorAB, (IInterfaceA,), IInterfaceB)
> gsm.registerAdapter(AdaptorBC, (IInterfaceB,), IInterfaceC)
> 
> objectA = ClassA()
> 
> # You can manually create the chain as follows, which works:
> b_like = IInterfaceB(objectA)
> c_like = IInterfaceC(b_like)
> 
> # But it appears that you cannot get the ZCA to resolve
> # the required chain as this line produces an error:
> c_like = IInterfaceC(objectA)
> 
> # c_like = getAdapter(objectA, IInterfaceC) also fails.


To adapt A to C you have to define a specific adapter to do this adaption. This adapter could look like this:

@zope.component.adapter(InterfaceA)
@zope.interface.implementer(InterfaceC)
def adaptAC(a):
    return InterfaceC(InterfaceB(a))

(You still have to register this adapter but the decorators make it easier to register it via ZCML.)

The reason why this does not work out of the box is that zope.component had to guess the chain. It had to do conflict resolution when there is more than one chain. Think of chains with more than two elements, this can lead to a huge matrix of possible chains where each has to be tested if it works.

And at least: explicit is better than implicit.

Yours sincerely,
-- 
Michael Howitz · mh at gocept.com · software developer
gocept gmbh & co. kg · forsterstraße 29 · 06112 halle (saale) · germany
http://gocept.com · tel +49 345 1229889 8 · fax +49 345 1229889 1
Zope and Plone consulting and development



More information about the bluebream mailing list