Welcome, guest | Sign In | My Account | Store | Cart

Notice! PyPM is being replaced with the ActiveState Platform, which enhances PyPM’s build and deploy capabilities. Create your free Platform account to download ActivePython or customize Python with the packages you require and get automatic updates.

pypm install z3c.layout

How to install z3c.layout

  1. Download and install ActivePython
  2. Open Command Prompt
  3. Type pypm install z3c.layout
 Python 2.7Python 3.2Python 3.3
Windows (32-bit)
0.2 Available View build log
Windows (64-bit)
0.2 Available View build log
Mac OS X (10.5+)
0.2 Available View build log
Linux (32-bit)
0.2 Available View build log
Linux (64-bit)
0.2 Available View build log
ZPL 2.1
Lastest release
version 0.2 on Jan 5th, 2011

HTML layout engine

This package implements a page rendering model based on a static HTML document that is made dynamic from the outside by mapping content provider definitions to locations in the HTML document tree. This is called a "layout".

The component architecture is utilized to provide extension points that allow wide application. Two-phase rendering is supported using the zope.contentprovider rendering scheme (update/render).

Static resources, as referenced by the HTML document (images, stylesheets and javascript files) are included carbon copy and published as browser resources (see zope.app.publisher.browser).


  • No template language required
  • Support for two-phase rendering
  • Integrates with creative workflow
  • Flexible extension points


Layouts and regions

Let's begin by instantiating a layout. We'll do this manually for the sake of this demonstration; usually this is done using the included ZCML-directive <browser:layout>.

>>> from z3c.layout.model import Layout
>>> layout = Layout(
...     "test", "%s/templates/default/index.html" % test_path, "test")

Register resource directory.

>>> import zope.configuration.config as config
>>> context = config.ConfigurationMachine()
>>> from zope.app.publisher.browser import resourcemeta
>>> resourcemeta.resourceDirectory(
...     context, "test", "%s/templates/default" % test_path)
>>> context.execute_actions()

Layouts are made dynamic by defining one or more regions. They are mapped to HTML locations using an xpath-expression and an insertion mode, which is one of "replace", "append", "prepend", "before" or "after".

Regions can specify the name of a content provider directly or it may rely on adaptation to yield a content provider component. We'll investigate both of these approaches:

>>> from z3c.layout.model import Region

First we define a title region where we directly specify the name of a content provider.

>>> title = Region("title", ".//title", title=u"Title", provider="title")

Then a content region where we leave it the content provider to component adaptation.

>>> content = Region("content", ".//div", "Content")

To register them with the layout we simply add them.

>>> layout.regions.add(title)
>>> layout.regions.add(content)

Let's define a context class.

>>> class MockContext(object):
...     interface.implements(interface.Interface)

We need to provide a general adapter that can provide content providers for regions that do not specify them directly. As an example, we'll define an adapter that simply tries to lookup a content provider with the same name as the region.

>>> from z3c.layout.interfaces import IContentProviderFactory
>>> class EponymousContentProviderFactory(object):
...     interface.implements(IContentProviderFactory)
...     def __init__(self, region):
...         self.region = region
...     def __call__(self, context, request, view):
...         name = self.region.name
...         return component.getMultiAdapter(
...            (view.context, request, view), IContentProvider, name)
>>> from z3c.layout.interfaces import IRegion
>>> component.provideAdapter(
...     EponymousContentProviderFactory, (IRegion,))

Before we can render the layout, we need to register content providers for the two regions. We'll use a mock class for demonstration.

>>> from zope.contentprovider.interfaces import IContentProvider
>>> class MockContentProvider(object):
...     interface.implements(IContentProvider)
...     __name__ = u""
...     def __init__(self, *args):
...         pass
...     def update(self):
...         pass
...     def render(self):
...         return self.__name__
...     def __repr__(self):
...         return "<MockContentProvider '%s'>" % self.__name__
>>> from zope.publisher.interfaces.browser import IBrowserRequest
>>> from zope.publisher.interfaces.browser import IBrowserView
>>> component.provideAdapter(
...     MockContentProvider, (MockContext, IBrowserRequest, IBrowserView),
...     name="title")
>>> component.provideAdapter(
...     MockContentProvider, (MockContext, IBrowserRequest, IBrowserView),
...     name="content")

Let's instantiate the layout browser-view. We must define a context and set up a request.

>>> from zope.publisher.browser import TestRequest
>>> context = MockContext()
>>> request = TestRequest()

We need to have the request be annotatable.

>>> from zope.annotation.attribute import AttributeAnnotations
>>> component.provideAdapter(
...     AttributeAnnotations, (TestRequest,))

The view expects the context to adapt to ILayout.

>>> from z3c.layout.interfaces import ILayout
>>> component.provideAdapter(
...     lambda context: layout, (MockContext,), ILayout)
>>> from z3c.layout.browser.layout import LayoutView
>>> view = LayoutView(context, request)

Verify that the layout view is able to get to these providers.

>>> view.mapping
(<Region 'content' .//div (replace) None>, <MockContentProvider 'content'>),
(<Region 'title' .//title (replace) 'title'>, <MockContentProvider 'title'>)}

Now for the actual output.

>>> print view()
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<link rel="stylesheet" href="test/main.css" type="text/css" media="screen">
<div id="content">content</div>

To support special cases where you need to use Python to transform the static HTML document at compile time, one or more transforms may be defined.

>>> from z3c.layout.model import Transform

Let's add a transform that adds a language setting to the <html>-tag.

>>> def set_language(node):
...     node.attrib["lang"] = "en"
>>> layout.transforms.add(
...    Transform(set_language))
>>> layout.parse().getroot().attrib["lang"]

And another transform that assigns a class to the <body>-tag.

>>> def set_class(node, value):
...     node.attrib["class"] = value
>>> layout.transforms.add(
...    Transform(lambda body: set_class(body, "front-page"), ".//body"))
>>> layout.parse().xpath('.//body')[0].attrib["class"]

Subscribe to package updates

Last updated Jan 5th, 2011

Download Stats

Last month:1

What does the lock icon mean?

Builds marked with a lock icon are only available via PyPM to users with a current ActivePython Business Edition subscription.

Need custom builds or support?

ActivePython Enterprise Edition guarantees priority access to technical support, indemnification, expert consulting and quality-assured language builds.

Plan on re-distributing ActivePython?

Get re-distribution rights and eliminate legal risks with ActivePython OEM Edition.