# HG changeset patch # User cmlenz # Date 1271447905 0 # Node ID 0849dcc8ed4645102f325f6b29a636b5e7fdb305 # Parent 6f49c23045b19bac42c56291f9805ecaf84c4a90 Added a documentation page about the template loader. diff --git a/doc/index.txt b/doc/index.txt --- a/doc/index.txt +++ b/doc/index.txt @@ -33,6 +33,7 @@ * `Templating Basics `_ * `XML Template Language `_ * `Text Template Language `_ +* `Loading Templates `_ * `Using Stream Filters `_ * `Using XPath `_ * `Internationalization and Localization `_ diff --git a/doc/loader.txt b/doc/loader.txt new file mode 100644 --- /dev/null +++ b/doc/loader.txt @@ -0,0 +1,223 @@ +.. -*- 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') + + +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) + + + +------- +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') + + +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. diff --git a/doc/upgrade.txt b/doc/upgrade.txt --- a/doc/upgrade.txt +++ b/doc/upgrade.txt @@ -18,6 +18,11 @@ Support for Python 2.3 has been dropped in this release. Python 2.4 is now the minimum version of Python required to run Genshi. +The XPath engine has been completely overhauled for this version. Some +patterns that previously matched incorrectly will no longer match, and +the other way around. In such cases, the XPath expressions need to be +fixed in your application and templates. + ------------------------------------ Upgrading from Genshi 0.4.x to 0.5.x