Registration

In the course of this narrative we will demonstrate different usage scenarios. The example test setup contains the following files:

./skins/index.pt
./skins/main_template.pt
./skins/images/logo.png
./skins/about/index.pt
./skins/about/images/logo.png

       ↳ mount point

To explain this setup, imagine that the index.pt template represents some page in the site (e.g. the front page); it uses main_template.pt as the o-wrap template. The about directory represents some editorial about-section where about/index.pt is the index page. This section provides its own logo.

We begin by registering the directory. This makes the files listed above available as skin components. The ZCML-directive skins makes registration easy:

<configure xmlns="http://pylonshq.com/pyramid">
  <include package="pyramid_skins" />
  <skins path="skins" />
</configure>

The path parameter indicates a relative path which defines the mount point for the skin registration.

Components

At this point the skin objects are available as utility components. This is the low-level interface:

from zope.component import getUtility
from pyramid_skins.interfaces import ISkinObject
index = getUtility(ISkinObject, name="index")

The component name is available in the name attribute:

index.name

We now move up one layer and consider the skin components as objects.

Objects

The SkinObject class itself wraps the low-level utility lookup:

from pyramid_skins import SkinObject
FrontPage = SkinObject("index")

This object is a callable which will render the template to a response (it could be an image, stylesheet or some other resource type). In the case of templates, the first two positional arguments (if given) are mapped to context and request. These symbols are available for use in the template.

response = FrontPage(u"Hello world!")

The index template simply inserts the context value into the body tag of the HTML document:

<html>
  <body>
    Hello world!
  </body>
</html>

The exact same approach works for the logo object:

from pyramid_skins import SkinObject
logo = SkinObject("images/logo.png")

Calling the logo object returns an HTTP response:

200 OK

Request-specific skins

Instead of global utility skin components, we can provide a request type:

<configure xmlns="http://pylonshq.com/pyramid">
  <include package="pyramid_skins" />
  <skins path="skins" request_type="pyramid.interfaces.IRequest" />
</configure>

The skin component is now registered as a named adapter on the request:

>>> from pyramid.testing import DummyRequest
>>> request = DummyRequest()

We use the getAdapter call:

>>> from zope.component import getAdapter
>>> getAdapter(request, ISkinObject, name="index")
<pyramid_skins.models.SkinTemplate name="index" path=".../skins/index.pt" at ...>

Views

The call method signature for skin templates is (context, request). This is the same as views. That is, we can use skin template objects directly as view callables:

<view name="frontpage1" view=".FrontPage" />

In Pyramid we can also define a view using a class which provides __init__ and __call__. The call method must return a response. With skin objects, we can express it this way:

class FrontPageView(object):
    __call__ = SkinObject("index")

    def __init__(self, context, request):
        self.context = context
        self.request = request

When the __call__ attribute is accessed (as a descriptor), a view callable is returned, bound to the view’s instance dictionary (which in this case has the symbols context and request):

<div id="view-${type(view).__name__.lower()}">
  <a href="${request.route_url('search')">Search</a>

  <p class="content">
    ${context}
  </p>
</div>

Note that methods are not bound.

<view name=”frontpage2” view=”.FrontPageView” />

While the two patterns are equivalent, using a view allows you to prepare data for the template. Both yield the exact same output when passed 'Hello world!' as the view context:

<html>
  <body>
    Hello world!
  </body>
</html>

Renderer

The package comes with a renderer factory for skin objects. It looks up a skin object based on view name.

pyramid_skins.renderer.renderer_factory(info)

Renders a skin object based on view name.

In your application setup, use the add_renderer method:

config.add_renderer('skin', renderer_factory)

Example view:

@view_config(name='index', renderer='skin')
def index(request):
    return {'title': 'My application'}

Discovery

In some scenarios, it’s useful to be able to discover skin objects at run-time. An example is when you use skins to publish editorial content which is added to the file system.

The discovery parameter takes a boolean argument, e.g. True:

<configure xmlns="http://pylonshq.com/pyramid">
  <skins path="skins" discovery="True" />
</configure>

Let’s add a new skin template with the source:

<div>Hello world!</div>

Compatibility

  • Mac OS X 10.5+ (requires the MacFSEvents library)
  • Linux 2.6.13+ with Libc >= 2.4 (requires pyinotify library)

Imperative configuration

If you prefer imperative configuration over declarative you can use the pyramid_skins.configuration.register_path method for configuration:

pyramid_skins.configuration.register_path(config, spec, discovery=False, indexes=[], request_type=None)

Add a skin path to the current configuration state.

If discovery is enabled, the path will automatically be monitored for changes.

The indexes argument is an optional list of view registrations with the provided names.

The request_type option decides the request type for which to make the registration.

Example:

from pyramid.config import Configurator
config = Configurator()

from pyramid_skins.configuration import register_path
register_path(config, path)

Table Of Contents

Previous topic

The flexible skinning solution

Next topic

Templates

This Page