This is the talk I gave on the Zope Component Architecture at Europython 2010. It gives a general outline of the ZCA concepts (Interfaces, Utilities and Adaptors) along with two examples where the ZCA would be useful.
2. Overview
• A real world problem.
• An explanation of the core ZCA concepts.
• A simple model of the problem to use during the talk.
• Code to apply concepts in the context of the simple
model.
4. The newsletter problem
• Types designed for display on the web which we couldn't
edit.
• But which were in a good class hierarchy.
• But we need to reformat some of them for display in a
newsletter—and format the rest in a generic manner.
• And, as always, we’re on a deadline.
• The ZCA can help us with this problem
5. A “standard”
A Typical Day
As Gregor Samsa awoke one morning from
item just gets
uneasy dreams he found himself transformed a title and
in his bed into a monstrous vermin. More...
description.
Birthday News: “I feel no older” A news item
After celebrating his 27th birthday, gets a picture
a man claimed today to “feel no
older” than the day before. More... beside it.
Paris in the Autumn view the album And for a
photo album,
why not just
some photos?
6. Modelling the problem
• I’m going to use the problem I just described as a basis.
• We’re going to work through a simplified version to go
over the primary concepts in the ZCA.
• First, let’s look at the concepts.
8. Let’s talk about Zope
• Zope = Zope Object Publishing Environment.
• Zope’s model is that of an object graph.
• Both content and functionality are stored in Zope’s object
database (the ZODB).
• Zope 2 was a bit all or nothing: inventing wheels, very
interwoven.
10. Zope 3
• Zope 3 was the reformulation of Zope into components.
• The ZCA was built to meld these components together
into a web platform.
• It’s not crazy.
11. The ZCA
• A Service Locator—it helps the parts of
your application find each other without
tight coupling.
• Components are registered with a central
registry, which responds to queries.
• Configuration decides what component
provides a given function.
• Though it would be possible to write a
plugin architecture for your project, the ZCA
is already there and well tested.
We provide I need
function X function X
I can help
12. Interfaces
• Defines a set of functionality a thing promises to provide.
• A gentleman’s agreement, not a contract.
• Can be implemented any object, unlike some other
languages.
• The core of the ZCA:
• You can ask for an object which implements an interface;
• Or an object to convert from one interface to another.
13. Interfaces
ZODB
LDAP User Code
SQL DB isValidUser()
addUser()
removeUser()
ISecurityProvider
14. Utilities
• A utility is an object which implements a specific interface.
• You register the object with the ZCA, telling the ZCA the
object is a utility which implements the interface.
• Then ask for it later from anywhere in your program.
15. Utilities
ZODB
LDAP User Code
SQL DB isValidUser()
addUser()
removeUser()
“implements”
ISecurityProvider
16. Adapters
• Adapters can convert from one or more interface to
another.
• In Zope they are often used to add functionality in addition
to just altering and interface.
17. Adapters
SQL DB Adapter User Code
userIsOkay()
userIsOkay()
isValidUser()
isValidUser() addUser()
removeUser()
ISecurityProvider
18. Multi-Adaptors
• Multi-adaptors adapt more than one input interface to a
single output interface.
• Zope uses this for rendering pages by adapting as follows:
HTTP Request
View
Adapter (rendered page)
Content Item
19. Is this too far?
• Zope 3 uses multi-adaptors to register event handlers:
Like the snappily named
Event type is IObjectModifiedEvent
defined by
Interface
Callable which
Adapter
handles event
Content Item
21. The simplified model
Finder
Selects items for
sending
Content to
select from. IItemFinder
Renderer for most items Rendering
“Pipeline”
Renderer for news items
Renderer for photo albums
INewsletterItemRenderer
23. The content objects
# Note they have no knowledge of the
# ZCA.
class StandardItem(object): class NewsItem(StandardItem):
def __init__(self, title): def __init__(self, title,
self.title = title description, date):
self.title = title
@property self.description = description
def url(self): self.date = date
"""Generate a url"""
[...]
class SubStandardItem(StandardItem): class PhotoAlbum(StandardItem):
"""This item should be renderable
by the adaptor for StandardItem""" def __init__(self, title,
thumbnails):
def __init__(self, title): self.title = title
self.title = "SUB! %s" % title self.thumbnails = thumbnails
24. A utility to find them
class IItemFinder(Interface):
def __call__():
"""Return a list of items which descend from StandardItem."""
class ItemFinder(object):
implements(IItemFinder)
def __call__(self): The ZCA bits
"""Hardcode for demo purposes"""
return [
PhotoAlbum("Crocodiles", []),
StandardItem("A Standard Item"),
SubStandardItem("A second standard item"),
NewsItem("Man Feels No Different on Birthday",
"""
Man reports feeling no different on 27th birthday
from the day before.""",
"10th July, 2010"),
NewsItem("Less Newsworthy",
"""
The world is going to end tomorrow at 14.27.""",
"13th June, 2010"),
[... some more items ...]
]
25. Adaptors to render them
class INewsletterItemRenderer(Interface):
def render(): Our interface
"""Render an item"""
class BaseRenderer():
"""Base class to do what all the renderers need to do"""All renderers
implements(INewsletterItemRenderer)
def __init__(self, context): implement
self.context = context
class BaseContentToNewsletterBlockRenderer(BaseRenderer):
the interface
adapts(StandardItem)
def render(self): and adapt a
return "*** %s (Standard Item)n %s" % (
self.context.title, self.context.url) content item
class NewsItemToNewsletterBlockRenderer(BaseRenderer): to it
adapts(NewsItem)
def render(self):
return "*** %s (News)n %sn %snn %s" % (
self.context.title, self.context.date, self.context.url,
[...format the body...]
class PhotoAlbumToNewsletterBlockRenderer(BaseRenderer):
[...]
26. Register them
# These all use the Global registry. It's possible to
# have separate registries if needed for your application.
from zope.component import provideAdapter, provideUtility,
getUtility
# (1) A utility needs to be instantiated before registering.
provideUtility(ItemFinder(), IItemFinder)
# (2) Adaptors will be created as needed so don’t need
# creating.
provideAdapter(BaseContentToNewsletterBlockRenderer,
(StandardItem,),
INewsletterItemRenderer)
provideAdapter(NewsItemToNewsletterBlockRenderer,
(NewsItem,),
INewsletterItemRenderer)
provideAdapter(PhotoAlbumToNewsletterBlockRenderer,
(PhotoAlbum,),
INewsletterItemRenderer)
27. And use them
Get the utility and call it to get item list:
finder = getUtility(IItemFinder)
items = finder()
The ZCA will find the right renderer:
body = "nn".join([
INewsletterBlockRenderer(x).render() for x in finder ])
Let’s go!
print """
Dear subscriber,
%s
We hope you enjoyed this update,
The Team.
""" % body
28. Summary
• ZCA allows for building robustly componentised applications.
• Core is: Interfaces, Utilities and Adapters.
• It’s well tested and small enough to easily learn.
• It’s powerful enough for production use--and widely
deployed.
• Suggested further reading:
http://www.muthukadan.net/docs/zca.html
29. Get in contact:
mike@netsight.co.uk
Thank you for watching! Or catch me in the hallways!