3

I have next class:

@implementer(ISocial)
class SocialVKSelenium:
    pass

And when I add it to zope registry:

gsm = getGlobalSiteManager()
gsm.registerAdapter(SocialVKSelenium)

I got: TypeError: The adapter factory doesn't have a __component_adapts__ attribute and no required specifications were specified

When I add there adapter(IOther), the registration works as expected, but without is not. Why does it happens?

eirenikos
  • 2,296
  • 25
  • 25
  • Is this "pure" Zope 3 application? Usually something built on the top of Zope provides the registry. – Mikko Ohtamaa Jan 30 '17 at 08:37
  • @MikkoOhtamaa I'm looking a way to use some registry for a separated component. But I think I'm doing something wrong, I had a misunderstanding of zca concept. – eirenikos Jan 30 '17 at 11:23
  • You likely need a clear idea of what you are adapting from, e.g. what is the context object that is adapted? Should you want an adapter that can adapt a variety of different kinds of objects, there are a variety of ways to accomplish that, but the simplest case of adapter has a clear source interface (from/adapts) and destination interface (to/implements). – sdupton Jan 30 '17 at 18:00
  • It's always interesting to come back to q&a in SO. I'm not even remember why I was doing this thing XD – eirenikos Jan 30 '21 at 12:46

1 Answers1

3

You need to provide a context, either on the class, or to the registry.

I suspect that you are not communicating the entirety of your problem set -- an adapter is a component that adapts an object of a specified interface, and provides another. Your example fails to specify what the context being adapted is, that is, what kind of object is adapted on construction of your adapter object by its class?

For example, this works fine:

from zope.interface import Interface, implements
from zope.component import getGlobalSiteManager, adapts


class IWeight(Interface):
    pass


class IVolume(Interface):
    pass

class WeightToVolume(object):
    implements(IVolume)
    adapts(IWeight)
    #...


gsm = getGlobalSiteManager()
gsm.registerAdapter(WeightToVolume)

While you can use the decorator (implementer/adapter) syntax for this, by convention, use of implements/adapts are preferred for adapter factories that are classes, not functions.

At the very minimum if your adapter does not declare what it adapts on the class or factory function itself, you will need to tell the registry. In the broadest case, this might look like:

gsm.registerAdapter(MyAdapterClassHere, required=(Interface,))

Of course, this example above is an adapter that claims to adapt any context, which is not recommended unless you know why you need that.

sdupton
  • 1,869
  • 10
  • 9
  • Thank you for clean explanation, now I understood the concept more. One more notice, that function `implements` doesn't work in Python 3, because there no __metaclass__ inside class scope. – eirenikos Jan 31 '17 at 09:25