Zope components

Why zope components?

Why didn't everybody switch to zope3?

It seems that not all good ideas make sense in the real world.

zope3 was designed to be a non-framework that allows you to choose whichever packages you like on your own. It was the answer to the monolithic approach of Zope2.

Think of gentoo's stage1 installation.

It turned out to be even more esoteric that Zope2.

And it was hard to bootstrap a new application.

Why should we use zope3 then?

Combine the important parts of zope3 with Zope2 (using Five) to create a Zope2 framework that is better than Zope2

Plone/Grok has been using components successfully for years and they don't want to switch back.

Allows sane code reuse - without sub-classing or import loops.

A decoupled architecture is always easier to refactor and improve upon.

Provide new functionality to class/collection of objects without actually modifying any code in the target classes.

Does not add a performance overhead. Looking up a component is equal to looking up a dictionary key.

Less monkey patches! Yeay!

So what exactly are zope components?

The components framework is implemented using zope.interface and zope.component.

Overview

This is how an application structure can look like.


##########################################################################
#                                                                        #
#                        Global component registry                       #
#                                                                        #
#   ##################################################################   #
#   #                                                                #   #
#   #   Component registry 1                Component registry 2     #   #
#   #                                                                #   #
#   #  ############################################################  #   #
#   #  #                            #                             #  #   #
#   #  #   Component registry 1.1   #                             #  #   #
#   #  #                            #                             #  #   #
#   #  # ########################## #                             #  #   #
#   #  # #                        # #                             #  #   #
#   #  # #  Events, Adapters,     # #    Events, Utilities,       #  #   #
#   #  # #  Utilities.            # #    Adapters, MultiAdapters  #  #   #
#   #  # #                        # #                             #  #   #
#   #  # ########################## #                             #  #   #
#   #  #                            #                             #  #   #
#   #  ############################################################  #   #
#   #                                                                #   #
#   ##################################################################   #
#                                                                        #
#                                                                        #
##########################################################################

Component registries? Events? Adapters?

Let's register an utility - it's easy!

We'll use the global site manager as our component registry.

from zope.component import getGlobalSiteManager
from zope.interface import Interface, implements

class IUtility(Interface):
    """ A generic utility interface """
    def do_stuff(param):
        """ A utility does things """

class SomeUtility(object):
    implements(IUtility)

    def do_stuff(self, name):
        print "Hello", name

gsm = getGlobalSiteManager()
gsm.registerUtility(SomeUtility(), IUtility)

now let's use it

from zope.component import getGlobalSiteManager
gsm = getGlobalSiteManager()
my_utility = gsm.getUtility(IUtility)
my_utility.do_stuff("Medved")

An adapter is easy too

Let's see how we can provide additional functionality to an object using adapters.

from zope.interface import implements, Interface
from zope.component import adapts
from zope.component import getGlobalSiteManager

class IDriver(Interface):
    """ """
class Driver(object):
    """ """
    implements(IDriver)

    def __init__(self, name):
        self.name = name

class ICar(Interface):
    """ """
class SuperCar(object):
    implements(ICar)
    adapts(IDriver)

    def __init__(self, driver):
        self.driver = driver # here is where we can connect the dots

    def super_drive(self):
        """ """
        print "%s, warp 9! Engage!" % self.driver.name

gsm = getGlobalSiteManager()
gsm.registerAdapter(SuperCar)

now let's call the adapter and see what happens.


>> driver = Driver("Data")
>> gsm.getAdapter(driver, ICar).super_drive()
Data, warp 9! Engage!

Event handlers

Create a document object and throw a created event when the document is created.

import datetime
from zope.interface import Interface, implements
from zope.component import adapter, handle, getGlobalSiteManager

class Document(object):
    def __init__(self):
        handle(DocumentCreated(self))

class IDocumentCreated(Interface):
    """ Marker interface for the event"""

class DocumentCreated(object):
    """ This class acts just like an adapter"""
    implements(IDocumentCreated)

    def __init__(self, doc):
        self.doc = doc

@adapter(IDocumentCreated)
def document_created_handler(event):
    event.doc.created = datetime.datetime.utcnow()

gsm = getGlobalSiteManager()
gsm.registerHandler(document_created_handler)

now when we create a dcoument and event will be thrown

>> doc = Document()
>> print doc.created
1999-01-01 14:28:10.282545

There's more

Thank you! Questions?

/

#