How can I get a list of Eventish content types?

Hi everyone,

I need to get a list of all content types that provides the plone.event.interfaces.IEvent interface.
I can get the list of all portal types with:

from plone import api

portal_types = api.portal.get_tool('portal_types')
type_list = portal_types.listContentTypes()
type_factories = portal_types.listTypeInfo()

But I can't figure out how to get the real class of the type to check with IEvent.providedBy(type_class)

Any advise will be appreciated!

1 Like

I suspect trying to get from content class is a trap: IEvent.implementedBy(type_class) assumes that the FTI is using something other than the default class (at least for Dexterity). Won't work for behavior-provided events, quite possibly. Better to look at the main interface and and behaviors configured on the FTI than trying to get a content implementation class from it.

Sean

we want to construct a dynamic list to replace the functionality provided in the past by portal_calendar:

we are thinking on using a catalog query we already have, to create a list of object providing the IEvent interface and then reduce that list to get all different type of portal types present on it.

Seems reasonable to query object_provides index, then get unique set of portal_type values from brains, if you memoize it. OTOH, not caching this is costly, and invalidation here is a pain: what happens when someone adds the first content item of a type that happens to be event-ish, and your cached list doesn't include its portal_type?

Is this Archetypes or Dexterity? If just Dexterity types plus built-in Event type on Plone 4, everything you need is likely in the FTI without resorting to walking your content or the catalog.

Sean

that's exactly our problem now: how do discover which IEvent interface to use, the one from ATContentTypes of the one from plone.event :slight_smile:

it must work in any of the following cases: vanilla Plone 4; Plone 4 with plone.app.contenttypes installed; vanilla Plone 5.

you can always use the catalog counter as a key for your cache to solve that kind of issues:

from plone.memoize import ram

def _catalog_counter_cachekey(method, self):
    """Return a cachekey based on catalog updates."""
    catalog = api.portal.get_tool('portal_catalog')
    return str(catalog.getCounter())

@ram.cache(_catalog_counter_cachekey)
def your_expensive_method(self):
    # do expensive things

That did not occur to me, but it makes sense.

If you have a site that you know that no instance is marked with a behavior that its type is not [1], you can also get this just by looking at the Dexterity FTI 'schema' and 'behaviors' attributes, without ever resorting to a catalog query [2].

[1] (per-instance behaviors are uncommon, though possible). E.g. if you have a scenario where you have a page that is also an event.

[2] I have no idea what happens when/if tiles overthrow content types for things like this.

Sean

we have changed our approach as maintaining a fork of the calendar code makes absolutely no sense.

we're going to use the calendar portlets as helper views inside the tile.

This should work:

from plone.dexterity.utils import resolveDottedName
event_types = [type.klass for type in api.portal.get_tool(name='portal_types').values() if hasattr(type, 'klass') and IEvent.implementedBy(resolveDottedName(type.klass))]
1 Like

resolveDottedName is new for me! thanks for the tip!

1 Like

maybe this should be changed with safe_hasattr or getattr(type, 'klass', None) is not None