Utilities

Description

Utility design pattern in Zope 3 allows easily overridable singleton class instances for your code.

Introduction

  • Utility classes provide site-wide utility functions.
  • They are registered by marker interfaces.
  • Site customization logic or add-on products can override utility for enhanced or modified functionality
  • Utilities can be looked up by name or interface
  • Compared to "plain Python functions" utiltiies provide the advantage of being plug-in points without need of monkey-patching

Read more in

Local and global utilities

Utilities can be

  • global - registered during Zope start-up
  • local - registered during add-on installer for a certain site/content item

Local utilities are registered to persistent object. The context of local utilities is stored in a thread local variable which is set during the traversing. Thus, when you ask for local utilities, they usually come from persistent registry set up in the Plone site root object.

Global utilities are registered in ZCML and affect all Zope application server and Plone site instances.

Some hints:

<Moo^_^> what's difference between gsm.queryUtility() (global site manager) and zope.component.queryUtility()
<agroszer> Moo^_^, I think gsm... takes the global registrations, z.c.queryUtility respects the current context

Registering a global utility

Utility is constructed when Plone is started and ZCML is read. Utilities take no constructor parameters. If you need to use parameters like context or request, consider using views or adapters instead. Utilities may or may not have a name.

  • Utility can be provided by a function: function is being called and it returns utility object
  • Utility can be provided by a class: class __call__() method itself acts as an factory and returns new class instance

ZCML example:

<!-- Register header animation picking logic - override this for your custom logic -->
<utility
  provides="gomobile.convergence.interfaces.IConvergenceMediaFilter"
  factory=".filter.ConvergedMediaFilter" />

Python example (named utility):

def registerOnsitePaymentProcessor(processor_class):
    """ """

    # Make OnsitePaymentProcessor class available as utiltiy
    processor = processor_class()
    gsm = component.getGlobalSiteManager()
    gsm.registerUtility(processor, interfaces.IOnsitePaymentProcessor, processor.name)

The utility class "factory" is in its simplest form a class which implements the interface:

class ConvergedMediaFilter(object):
    """ Helper class to deal with media state of content objects.

    """

    zope.interface.implements(IConvergenceMediaFilter)

    def foobar(x):
        """ An example method """
        return x+2

Class is constructed / factory is run during the ZCML initialization.

To use this class:

from gomobile.convergence.interfaces import IConvergenceMediaFilter

def something():
   filter = getUtility(IConvergenceMediaFilter)
   x = filter.foobar(3)

Overriding utility

If you want to override any existing utility you can re-register the utility in overrides.zcml file in your product.

Getting utility

There are two functions

  • zope.component.getUtility will raise exception if utility is not found
  • zope.component.queryUtility will return None if utility is not found

Utility query parameters are passed to the utility class constructor.

Example:

from zope.component import getUtility, queryUtility

# context and request are passed to the utility class constructor
# they are optional and depend on the utility itself
picker = getUtility(IHeaderAnimationPicker, context, request)

Note

You cannot use getUtility() on Python module body level code during import, as Zope Component Architecture is not yet initialized. Always call getUtility() from HTTP request end point or after Zope has been started.

Query local + global utilities:

``zope.component.queryUtility()`` for local utilities, with global fallback.

Query only global utilities:

from zope.app import zapi
gsm = zapi.getGlobalSiteManager()
return gsm.getUtility(IConvergenceMediaFilter)

Warning

Due to Zope component architecture initialization order, you cannot call getUtility() in module level Python code. Module level Python code is run when the module is being imported, and Zope components are not yet necessary set up in this point.

Getting all named utilities of one interface

Use zope.component.getUtilitiesFor().

Example

def OnsitePaymentProcessors(context):
    """ List all registered on-site payment processors.

    Mostly useful for validating form input.

    Vocabulary contains all payment processors, not just active ones.

    @return: zope.vocabulary.SimpleVocabulary
    """
    utilities = component.getUtilitiesFor(interfaces.IOnsitePaymentProcessor)
    for name, instance in utilities:
        pass



Edit this document

The source code of this file is hosted on GitHub. Everyone can update and fix errors in this document with few clicks - no downloads needed.

  1. Go to Utilities on GitHub.
  2. Press Fork and edit this file button.
  3. Edit file contents using GitHub's text editor in your web browserm
  4. Fill in the Commit message text box at the end of the page telling why you did the changes. Press Propose file change button next to it when done.
  5. On Send a pull request page you don't need to fill in text anymore. Just press Send pull request button.
  6. Your changes are now queued for review under project's Pull requests tab on Github.

For basic information about updating this manual and Sphinx format please see Writing and updating the manual guide.