5

The question says everything. Or am I trying to use zope.interface for the wrong purpose?

What I need is basically the One Way To Do It for registering classes that implement a certain functionality (Widgets or Portlets for a CMS). Basically like django does with its ModelAdmin classes, but not automatic and not magic.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Luiz Geron
  • 1,357
  • 15
  • 22
  • Can't you just do `list(zope.interface.implements(myInterface))`? – agf Aug 05 '11 at 21:41
  • 1
    @agf No, that method does not do what you think it does. zope.interface.implements lists the interfaces a given object claims to implement. It's not a list of classes that implement a given interface. – Martijn Pieters Aug 06 '11 at 12:59

2 Answers2

3

This is what the zope.component architecture solves, but you must register all uses of an interface. By itself, zope.interface does not keep track of what objects implement a given interface.

What you are looking for is utility registrations; all implementations of a given service as defined by an interface.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • How can i do that more specifically? I couldn't find a method that would let me register 2 different utilities for the same interface (the latest registered is always the only one I can find later). It seems to me this is isn't how utilities are supposed to be used, the docs always use instances on the examples and generating an unique name for each registration seems like a huge and ugly hack. – Luiz Geron Aug 06 '11 at 15:25
  • 1
    No, you name them all, this is by design. You can then list all utilities for a given interface and you can then pick a specific one by name if need be. Alternatively, use a different registration method, such as a ZCatalog index (indexing identifiers); Plone uses both methods. – Martijn Pieters Aug 06 '11 at 15:31
  • ZCatalog seems to be way far from what I looking for. From what I could gather, it is an index tool for ZODB, and what I need has nothing to do with any sort of storage, just a class registry. – Luiz Geron Aug 06 '11 at 16:38
  • 2
    Martijn is just citing ZCatalog as an example. For every class you want to query on a per-implemented interface basis, you will have to register that class as a utility in the ZCA, as Martijn is saying. IOW, you have to explicitly register them to be able to query them as you ask. – Ross Patterson Aug 12 '11 at 10:34
1

The simplest approach is to decorate zope.interface.declarations.classImplements (and its alias zope.interface.classImplements).

from zope import interface as i
from collections import defaultdict
oclassImplements = i.classImplements
registry = defaultdict(list)
def classImplements(cls, *interfaces):
    for a in interfaces:
        registry[a].append(cls)
    return oclassImplements(cls, *interfaces)
i.classImplements = i.declarations.classImplements = classImplements

Note that you must do this before the interfaces you want to catch are implemented, usually it's best to do this before importing anything else.

Perkins
  • 2,409
  • 25
  • 23