view doc/loader.txt @ 883:0849dcc8ed46

Added a documentation page about the template loader.
author cmlenz
date Fri, 16 Apr 2010 19:58:25 +0000
parents
children 5a1c0ee0f659
line wrap: on
line source
.. -*- mode: rst; encoding: utf-8 -*-

=================
Loading Templates
=================

Genshi comes with a simple but flexible implementation of a template loader in
the ``genshi.template.loader`` module. The loader provides caching of
templates so they do not need to be reparsed when used, support for multiple
template directories that together form a virtual search path, as well as
support for different template loading strategies.

.. contents:: Contents
   :depth: 3
.. sectnum::


-----
Usage
-----

The basic usage pattern is simple: instantiate one ``TemplateLoader`` object
and keep it around, then ask it to load a template whenever you need to load
one:

.. code-block:: pycon

  >>> from genshi.template import TemplateLoader
  
  >>> loader = TemplateLoader(['/path/to/dir1', '/path/to/dir2'],
  ...                         auto_reload=True)
  >>> loader.load('test.html')
  <MarkupTemplate "test.html">

When you try to load a template that can't be found, you get a
``TemplateNotFound`` error:

.. code-block:: pycon

  >>> loader.load('foobar.html')
  Traceback (most recent call last):
    ...
  TemplateNotFound: Template "foobar.html" not found

The default template class used by the loader is ``MarkupTemplate``, but that
can be overridden both with a different default (as a keyword argument to the
``TemplateLoader`` constructor), as well as for every individual invocation of
the ``load()`` method:

.. code-block:: pycon

  >>> from genshi.template.text import NewTextTemplate
  >>> loader.load('mail.txt', cls=NewTextTemplate)
  <NewTextTemplate "mail.txt">


-------
Caching
-------

The ``TemplateLoader`` class provides a simple in-memory cache for parsed
template objects. This improves performance, because templates do not need to
be reparsed every time they are rendered.

The size of this cache can be adjusted using the `max_cache_size` option on
the ``TemplateLoader`` constructor. The value of that option determines the
maximum number of template objects kept in the cache. When this limit is
reached, any templates that haven't been used in a while get purged.
Technically, this is a least-recently-used (LRU) cache.

Once a template has been cached, it will normally not get reparsed until it
has been purged from the cache. This means that any changes to the template
files are not taken into consideration as long as it is still found in the
cache. As this is inconvenient in development scenarios, the ``auto_reload``
option allows for automatic cache invalidation based on whether the template
source has changed. But in production environments, automatic reloading should
be disabled, as it does affect performance negatively.


--------------------
Template Search Path
--------------------

The template loader can be configured with a list of multiple directories in
which to search for templates. Taken together, these directories are mapped to
a single logical directory for locating templates by file name.

The order of the directories making up the search path is significant: the
loader will first try to locate a requested template in the first directory,
then in the second, and so on. If there are two templates with the same file
name in multiple directories on the search path, the file found first is used.

Based on this design, an application could, for example, configure a search
path consisting of a directory containing the default templates, as well as a
directory where site-specific templates can be stored that will override the
default templates.


Load Functions
==============

Usually the search path consists of strings representing directory paths, but
it may also contain “load functions”: functions that are basically invoked
with the file name, and return the template content.

Genshi comes with three builtin load functions:

``directory(path)``
-------------------

The equivalent of just using a string containing the directory path: looks up
the file name in a specific directory.

.. code-block:: pycon

  >>> from genshi.template import TemplateLoader, loader
  >>> tl = TemplateLoader([loader.directory('/path/to/dir/')])

That is the same as:

.. code-block:: pycon

  >>> tl = TemplateLoader(['/path/to/dir/'])


``package(name, path)``
-----------------------

Uses the ``pkg_resources`` API to locate files in Python package data (which
may be inside a ZIP archive).

.. code-block:: pycon

  >>> from genshi.template import TemplateLoader, loader
  >>> tl = TemplateLoader([loader.package('myapp', 'templates')])

This will look for templates in the ``templates`` directory of the Python
package ``myapp``.

``prefixed(**delegates)``
-------------------------

Delegates load requests to different load functions based on the path prefix.

.. code-block:: pycon

  >>> from genshi.template import TemplateLoader, loader
  >>> tl = TemplateLoader(loader.prefixed(
  ...   core = '/tmp/dir1',
  ...   plugin1 = loader.package('plugin1', 'templates'),
  ...   plugin2 = loader.package('plugin2', 'templates'),
  ... ))
  >>> tl.load('core/index.html')
  <MarkupTemplate "core/index.html">

This example sets up a loader with three delegates, under the prefixes “core”,
“plugin1”, and “plugin2”. When a template is requested the ``prefixed`` load
function looks for a delegate with a corresponding prefix, removes the prefix
from the path and asks the delegate to load the template.

In this case, assuming the directory ``/path/to/dir`` contains a file named
``index.html``, that file will be used when we load ``core/index.html``. The
other delegate are not checked as their prefix does not match.


.. note:: These builtin load functions are available both as class methods
          of the ``TemplateLoader`` class as well as on the module level


Custom Load Functions
---------------------

You can easily use your own load function with the template loader, for
example to load templates from a database. All that is needed is a callable
object that accepts a ``filename`` (a string) and returns a tuple of the form
``(filepath, filename, fileobj, uptodate_fun)``, where:

``filepath``
  is the absolute path to the template
``filename``
  is the base name of the template file
``fileobj``
  is a readable file-like object that provides the content of the template
``uptodate_fun``
  is a function that the loader can invoke to check whether the cached version
  of the template is still up-to-date, or ``None`` if the load function is not
  able to provide such a check. If provided, the function should not expect
  any parameters (so you'll definitely want to use a closure here), and should
  return ``True`` if the template has not changed since it was last loaded.

When the requested template can not be found, the function should raise an
``IOError`` or ``TemplateNotFound`` exception.


------------------
Customized Loading
------------------

If you require a completely different implementation of template loading, you
can extend or even replace the builtin ``TemplateLoader`` class.

Protocol
========

The protocol between the template loader and the templates itself is simple
and only used for processing includes. The only required part of that protocol
is that the object assigned to ``Template.loader`` implements a ``load``
method compatible to that of the ``TemplateLoader`` class, at the minimum with
the signature ``load(filename, relative_to=None, cls=None)``.

In addition, templates currently check for the existence and value of a boolean
``auto_reload`` property. If the property exists and evaluates to a non-truth
value, inlining of included templates is disabled. Inlining is a small
optimization that removes some overhead in the processing of includes.

Subclassing ``TemplateLoader``
==============================

You can also adjust the behavior of the ``TemplateLoader`` class by subclassing
it. You can of course override anything needed, but the class also provides the
``_instantiate()`` hook, which is intended for use by subclasses to customize
the creation of the template object from the file name and content. Please
consult the code and the API documentation for more detail.
Copyright (C) 2012-2017 Edgewall Software