How to enumerate all content types implementing a given interface

Plone: 5.2.2
Say I have an interface like this:

from zope.interface import Interface
class IMyResource(Interface):
    """Marker interface"""

And now I create some dexterity types that implement this interface

from ..interfaces import IMyResource
from plone.dexterity.content import Item
from plone.supermodel import model
from zope.interface import implementer

class IResourceA(model.Schema):
    """My schema for resource A"""

@implementer(IResourceA, IMyResource)
class ResourceA(Item):
    """My resource A"""

class IResourceB(model.Schema):
    """My schema for resource B"""

@implementer(IResourceB, IMyResource)
class ResourceB(Item):
    """My resource B"""

Of course ResourceA and ResourceB are registered with a corresponding type definition in profiles/default/types/ResourceX.xml and are addable within Plone.
Is there a way to enumerate all classes which implement the IMyResource interface?
The background is that I want to create a dynamic vocabulary which lists all the types that implement a given interface and there I need access to their portal_type, their name/title and maybe also to their description.

Hope you guys can help me. Thanks!

It will not be easy to determine for a given interface I all classes that implement I. implementer adds/extends the attribute __implements__ on the decorated object. It does not maintain at a central place which interfaces are implemented by which classes. Thus, at runtime, you best option would likely be to use the garbage collectors ability to determine for an object O the objects with a reference to O. Computing the transitive closure of this relation (truncated where the zope.interface world has been left` your should be able to locate the implementing classes. Possible -- but definitely not easy.

If you need this at runtime, use specialized decorators which maintain a central registry. Otherwise, an advanced search in the source code may provide preliminary information about the use of interface I.

Thank you, Dieter. I was hoping the implementer decorator already has a central registry for that. Using the garbage collectors knowledge sounds like a fun idea but maybe it is a bit too much for my case.

I think I am going to try a different approach then. Either iterating over all portal_types and checking their interfaces or creating my own decorator or a method to register a given class to a Interface, basically a dictionary from an interface to a set of classes/interfaces.

It looks now like this:

from Products.CMFCore.utils import getToolByName
from zope.interface import provider
from zope.schema.interfaces import IContextSourceBinder
from zope.schema.vocabulary import SimpleVocabulary
from plone.dexterity import utils

from my.plone.addon.interfaces import IMyResource

@provider(IContextSourceBinder)
def registeredResources(context):
    typeList = getToolByName(context, 'portal_types').listTypeInfo()

    terms = []
    for type in typeList:
        dottedName = getattr(type, 'klass', None)

        if dottedName is None:
            continue

        if not IMyResource.implementedBy(utils.resolveDottedName(dottedName)):
            continue

        terms.append(
            SimpleVocabulary.createTerm(
                type.id,
                type.title,
                type.description
            )
        )


    return SimpleVocabulary(terms)

What do you think? I don't like the utils.resolveDottedName very much but I found no other way around it. Seems slow to me. On the other side there are never as much types registered and in the end it runs in O(n). Should be fine.

I may could use filter(), map() or a generator but I don't know if this would make things much faster.

Help a catalog query for interfaces? see here.

Yes, I could use the catalog to find all objects implementing the given interface using object_provides but what I really want is the type information itself, not the objects of that type. And if there is no object of the type ResourceB the catalog wouldn't find it.

There is a "Content Types" vocabulary. Maybe you could use some code from there (and then just check for interfaces there or something else that you can filter on.

1 Like