A standardized Python templating language interface.
Python
Switch branches/tags
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
alacarte
cti
tests
.gitignore
README.textile
distribute_setup.py
setup.cfg
setup.py

README.textile

à la carte

|ˌä lä ˈkärt; lə|

A common templating and serialization interface for Python, esp. web applications.
  1. adjective
    (of a menu or restaurant) listing or serving food that can be ordered as separate items, rather than part of a set meal.
    (of food) available on such a menu.
  2. adverb
    as separately priced items from a menu, not as part of a set meal : wine and good food served à la carte.

The core of the API is for the generation of content from a named template, ostensibly on-disk though some engines support passing in strings instead of paths. Evaluated templates are returned as a 2-tuple of (None or str(content_type), unicode(content)), making à la carte very useful for re-use in web frameworks.

Background

There are a wide variety of templating languages available. In fact, Python seems to collect them. In general, there is no unified or consistent way to utilize these templating languages. Due to the learning curve, developers become hesitant to switch from one language to another. Many templating languages are also poorly documented.

An attempt was made by the TurboGears project to create a unified API called Buffet, used primarily by the CherryPy application server, though in some cases this API is more difficult to use than the raw template language. Other frameworks (like Pylons) utilize small helper functions, but require that the framework be updated to extend support to new templating engines.

The onus for ease of deployment should be on the templating engine creator, not the framework creator or front-end web developer.

Conventions Used in this Document

This document will be written similar to an RFC. The following is copied, with modification, from RFC 2119, for no other reason than that was the first result in the web search.

  1. The word must, or the terms required or shall, mean that the definition is an absolute requirement of the specification.
  2. The phrase must not, or the phrase shall not, mean that the definition is an absolute prohibition of the specification.
  3. The word should, or the adjective recommended, mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.
  4. The phrase should not, or the phrase not recommended mean that there may exist valid reasons in particular circumstances when the particular behavior is acceptable or even useful, but the full implications should be understood and the case carefully weighed before implementing any behavior described with this label.
  5. The word may, or the adjective optional, mean that an item is truly optional. One developer may choose to include the item because a particular task requires it or because the developer feels that it enhances an application while another vendor may omit the same item.

An implementation which does not include a particular option must be prepared to interoperate with another implementation which does include the option, though perhaps with reduced functionality. In the same vein an implementation which does include a particular option must be prepared to interoperate with another implementation which does not include the option (except, of course, for the feature the option provides.)

Application Programming Interfaces

Path Negotiation

Support for:

  • 'engine:package.templates.foo' — implicit filename extension, with ‘best guess’ from a prioritized list of default engines
  • 'engine:package.templates/foo.html' — explicit file path relative to package

Parts are optional; all of the following are legal:

  • 'json:' — pure engine, usually a serializer or a template loaded from an existing string
  • 'package.templates.foo' — defaulting the engine part, implicit filename extension
  • 'package/templates/foo.html' — defaulting the engine, explicit file path
  • '/var/www/htdocs/index.html' — absolute path
  • './views/edit.html' or '../../templates/master.html' — relative paths

Where the path is relative to is up to the framework making use of the template interface, though this defaults to the current working directory.

Engine API

The registered renderer (engine) callable must accept the following named arguments. These arguments are referenced by name but should be defined in this order to allow for easy manual use. Renderers should also accept an unlimited list of additional keyword arguments (which may be called options, as it is with the provided default engines), which are additional values that can be passed in from a combination of a stored configuration and call-time value.

There are several attributes of the engine that are used internally for specific purposes. All of these attributes are optional, and will default to None if not present.

  • mapping — a dictionary mapping extensions to content types

The argument specification is as follows, and may be implemented as either a class with a __call__ attribute or a simple function.

  • data — a value for use in the template (usually a dictionary)
  • template — an optional on-disk absolute path
  • **options — additional optional keyword arguments

The renderer must return a 2-tuple of:

  • None or str — content type
  • unicode — content

Engine Forms

An engine may be defined as a simple function. Simple functions must not store state between calls. If your template engine needs to keep state (e.g. a cache) then you must implement your engine interface as a new-style class. An example of a simple function:

def helloTemplate(data=dict(name='world'), template=None, **options):
    return 'text/plain', u"Hello %(name)s!" % data

If an engine is a new-style class (that does not subclass à la carte’s Engine helper class) initial options are passed to the __init__ method (assigned previously to Engines().options) with render-time options passed to __call__.

If you wish to use the Engine helper class you get template caching and automatic reloading of on-disk templates that are modified between calls. There are two methods you must define in your subclass, and you can override __init__ to perform custom initialization, and __call__ to override the template generation.

  • prepare(filename, **options) — load and return a template object for the cache
  • render(template, data, **options) — render and return a finished template

An example of a light-weight wrapper for the Mako templating language is as follows:

class Mako(Engine):
    def load(self, filename, **options):
        return Template(filename=filename)
        
    def render(self, template, data, **options):
        return None, template.render_unicode(**data)