Interfaces

Introduction

Interfaces define what methods object provides. Plone extensively uses interfaces to define APIs between different subsystems. They provide more consistent and declarative way to define bridges between two different things, when duck-typing is not enough.

Interface defines the shape of a hole where you can drop different pieces. The shape of the piece is defined by interface, but the implementation details like color, material, etc. can vary.

See zope.interface package README <http://pypi.python.org/pypi/zope.interface>.

Implementing one or multiple interfaces

Use zope.interface.implements() in your class body. Multiple interfaces can be separated as an argument list.

Example:

from zope.interface import implements
from collective.mountpoint.interfaces import ILocalSyncedContent
from ora.objects.interfaces import IORAResearcher

class MyContent(folder.ATFolder):
    """A Researcher synchronized from ORA"""
    implements(IORAResearcher, ILocalSyncedContent)

Checking whether object provides an interface

providedBy

In Python you can use code:

from yourpackage.interfaces import IMyInterface

if IMyInterface.providedBy(object):
        # do stuff
else:
        # was not kind of the object we wanted

plone_interface_info

In page templates you can use plone_interface_info helper view:

<div tal:define="iinfo context/@@plone_interface_info">
        <span tal:condition="pytohn:iinfo.provides('your.dotted.interface.IName')">
                Do stuff for
        </span>
</div>

See also

Getting interface string id

The interface id is stored in the __identifier__ attribute.

Example file yourpackage/interfaces.py

import zope.interface

class IFoo(zope.interface.Interface).
    pass


# id is yourpackage.interfaces.IFoo
id = IFoo.__identifier__

Note that this attribute does not respect import aliasing.

Example:

Products.ATContentTypes.interfaces.IATDocument.__identifier__ is
Products.ATContentTypes.interfaces.document.IATDocument

Getting interface class by its string id

Use zope.dottedname package.

Example:

import zope.interface
from zope.dottedname.resolve import resolve

class IFoo(zope.interface.Interface).
    pass


# id is yourpackage.interfaces.IFoo
id = IFoo.__identifier__

interface_class == resolve(id)

assert IFoo == interface_class

Applying interfaces for several content types

You can retrofit content types with a marker interface afterwards.

Example use cases

  • You want to assign a viewlet for a set of particular content types
  • You want to enable certain behavior on certain content types

Note

Retrofitting is needed only when you need to create a common nominator for several otherwise unrelated classes. You can use one existing class or interface as a context without explicitly creating a marker interface. Places accepting zope.interface.Interface as a context usually accept a normal Python class as well (isinstance behavior).

You can assign the marker interface for several classes in ZCML using <class> declaration:

<!-- List of content types where last modified viewlet is enabled -->
<class class="Products.ATContentTypes.content.document.ATDocument">
       <implements interface=".interfaces.ILastModifiedSupport" />
</class>

<class class="Products.ATContentTypes.content.event.ATEvent">
       <implements interface=".interfaces.ILastModifiedSupport" />
</class>

<class class="Products.ATContentTypes.content.newsitem.ATNewsItem">
       <implements interface=".interfaces.ILastModifiedSupport" />
</class>

Then we can have a viewlet for these content types only using the following (grok example):

from five import grok
from interfaces import ILastModifiedSupport
from plone.app.layout.viewlets.interfaces import IBelowContent

class LastModified(grok.Viewlet):
    """ Viewlet to show the document last modification time.

    This is enabled on Page, Event and News Item wich implement ILastModofiedSupport marker interface.
    """

    grok.context(ILastModifiedSupport)
    grok.viewletmanager(IBelowContent)

Related:

  • zope.dottedname allows you to resolve dotted names to Python objects

    manually

Dynamic marker interfaces

Zope allows to you to dynamically turn on and off interfaces on any content objects through ZMI. Choose any object and Interfaces tab.

Marker interfaces might need to be explicitly declared using ZCML <interface> directive, so that Zope finds them:

<!-- Declare marker interface, so that it is available in ZMI -->
<interface interface="mfabrik.app.interfaces.promotion.IPromotionsPage" />

Note

Interface dotted name must be directly to the interface class and not an import from other module, like __init__.py.