I'm currently experimenting with the ZCA and I've run into a bit of a hitch. The script below defines an IFuncttion
interface, which is used to create function objects that can be chained (i.e. monads).
In this example, I'm trying to create a simple writer monad as an adapter, but getMultiAdapter
is raising a ComponentLookupError
. Why is this?
from zope import component, interface
class IFunction(interface.Interface):
name = interface.Attribute('Name of the function object')
def __call__(*args, **kw):
"""Call the function"""
class Function(object):
name = ''
interface.implements(IFunction)
def __call__(self, *args, **kw):
return self.run(*args, **kw)
def run(self, *args, **kw):
raise NotImplementedError
class MWriter(object):
component.adapts(IFunction, IFunction)
interface.implements(IFunction)
def __init__(self, prv, nxt):
self.prev, self.next = prv, nxt
def bind(self, x, log=None):
log = log or []
result, line = self.prev(x)
log.append(line)
return self.next(result, log)
def __call__(self, *args, **kw):
return self.bind(*args, **kw)
class AddOne(Function):
name = 'addone'
def run(self, x):
return x + 1
class MulTwo(Function):
name = 'multwo'
def run(self, x):
return x * 2
component.provideAdapter(MWriter)
print component.getMultiAdapter((AddOne(), MulTwo()), MWriter)(11, [])
You should not pass in the adapter you want to look up to component.getMultiAdapter()
. The second argument to that function is the name used for named adapters, but your registration did not use a name.
Simply remove that second argument:
>>> component.getMultiAdapter((AddOne(), MulTwo()))
<__main__.MWriter object at 0x1072516d0>
Unfortunately, calling MWriter()
still fails because you expect self.prev()
to return a tuple:
result, line = self.prev(x)
but AddOne()
returns just the one integer:
class AddOne(Function):
name = 'addone'
def run(self, x):
return x + 1
so you get an exception:
>>> component.getMultiAdapter((AddOne(), MulTwo()))(11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 37, in __call__
File "<string>", line 32, in bind
TypeError: 'int' object is not iterable
Perhaps you wanted each Function()
to return the name as well as the result:
class Function(object):
name = ''
interface.implements(IFunction)
def __call__(self, *args, **kw):
return self.run(*args, **kw), self.name
def run(self, *args, **kw):
raise NotImplementedError
but then calling self.next()
fails because it doesn't accept the extra log
argument passed in.