# HG changeset patch # User cmlenz # Date 1271450428 0 # Node ID 5a1c0ee0f659e1f5aa630e7a563e14684a0387a4 # Parent 0849dcc8ed4645102f325f6b29a636b5e7fdb305 Improve the template loader docs. diff --git a/doc/i18n.txt b/doc/i18n.txt --- a/doc/i18n.txt +++ b/doc/i18n.txt @@ -205,7 +205,7 @@ template.filters.insert(0, Translator(translations.ugettext)) loader = TemplateLoader('templates', callback=template_loaded) - template = loader.load("...") + template = loader.load('test.html') This approach ensures that the filter is not added everytime the template is loaded, and thus being applied multiple times. diff --git a/doc/loader.txt b/doc/loader.txt --- a/doc/loader.txt +++ b/doc/loader.txt @@ -23,35 +23,27 @@ and keep it around, then ask it to load a template whenever you need to load one: -.. code-block:: pycon +.. code-block:: python - >>> from genshi.template import TemplateLoader + from genshi.template import TemplateLoader - >>> loader = TemplateLoader(['/path/to/dir1', '/path/to/dir2'], - ... auto_reload=True) - >>> loader.load('test.html') - + loader = TemplateLoader(['/path/to/dir1', '/path/to/dir2'], + auto_reload=True) + tmpl = 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 +``TemplateNotFound`` error. 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: +``TemplateLoader`` constructor), as well as on invocation of the ``load()`` +method: -.. code-block:: pycon +.. code-block:: python - >>> from genshi.template.text import NewTextTemplate - >>> loader.load('mail.txt', cls=NewTextTemplate) - + from genshi.template.text import NewTextTemplate + + tmpl = loader.load('mail.txt', cls=NewTextTemplate) ------- @@ -66,29 +58,69 @@ 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. +Technically, this is a least-recently-used (LRU) cache, the default limit is +set to 25 templates. + +Automatic Reloading +=================== 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 +file 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. +source has changed. +.. code-block:: python + + from genshi.template import TemplateLoader + + loader = TemplateLoader('templates', auto_reload=True, max_cache_size=100) + +In production environments, automatic reloading should be disabled, as it does +affect performance negatively. + +Callback Interface +================== + +Sometimes you need to make sure that templates get properly configured after +they have been loaded, but you only want to do that when the template is +actually loaded and parsed, not when it is returned from the cache. + +For such cases, the ``TemplateLoader`` provides a way to specify a callback +function that gets invoked whenever a template is loaded. You can specify that +callback by passing it into the loader constructor via the ``callback`` +keyword argument, or later by setting the attribute of the same name. The +callback function should expect a single argument, the template object. + +For example, to properly inject the `translation filter`_ into any loaded +template, you'd use code similar to this: + +.. code-block:: python + + from genshi.filters import Translator + from genshi.template import TemplateLoader + + def template_loaded(template): + template.filters.insert(0, Translator(translations.ugettext)) + + loader = TemplateLoader('templates', callback=template_loaded) + +.. _`translation filter`: i18n.html -------------------- 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 template loader can be configured with a list of multiple directories to +search for templates. The loader maps these directories 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. +loader will first try to locate a requested template in the first directory on +the path, then in the second, and so on. If there are two templates with the +same file name in multiple directories on the search path, whatever file is +found first gets 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 @@ -111,16 +143,16 @@ The equivalent of just using a string containing the directory path: looks up the file name in a specific directory. -.. code-block:: pycon +.. code-block:: python - >>> from genshi.template import TemplateLoader, loader - >>> tl = TemplateLoader([loader.directory('/path/to/dir/')]) + from genshi.template import TemplateLoader, loader + tl = TemplateLoader([loader.directory('/path/to/dir/')]) That is the same as: -.. code-block:: pycon +.. code-block:: python - >>> tl = TemplateLoader(['/path/to/dir/']) + tl = TemplateLoader(['/path/to/dir/']) ``package(name, path)`` @@ -129,10 +161,10 @@ Uses the ``pkg_resources`` API to locate files in Python package data (which may be inside a ZIP archive). -.. code-block:: pycon +.. code-block:: python - >>> from genshi.template import TemplateLoader, loader - >>> tl = TemplateLoader([loader.package('myapp', 'templates')]) + 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``. @@ -142,25 +174,24 @@ Delegates load requests to different load functions based on the path prefix. -.. code-block:: pycon +.. code-block:: python - >>> 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') - + from genshi.template import TemplateLoader, loader + tl = TemplateLoader(loader.prefixed( + core = '/tmp/dir1', + plugin1 = loader.package('plugin1', 'templates'), + plugin2 = loader.package('plugin2', 'templates'), + )) + tmpl = 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 +“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. +other delegates are not checked as their prefix does not match. .. note:: These builtin load functions are available both as class methods @@ -176,7 +207,8 @@ ``(filepath, filename, fileobj, uptodate_fun)``, where: ``filepath`` - is the absolute path to the template + is the absolute path to the template. This is primarily used for output in + tracebacks, and does not need to map to an actual path on the file system. ``filename`` is the base name of the template file ``fileobj`` @@ -202,7 +234,7 @@ Protocol ======== -The protocol between the template loader and the templates itself is simple +The protocol between the template loader and the ``Template`` class 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 diff --git a/doc/templates.txt b/doc/templates.txt --- a/doc/templates.txt +++ b/doc/templates.txt @@ -142,7 +142,7 @@ .. _`Text Template Language`: text-templates.html .. _`Markup Streams`: streams.html -Using a template loader provides the advantage that “compiled” templates are +Using a `template loader`_ provides the advantage that “compiled” templates are automatically cached, and only parsed again when the template file changes. In addition, it enables the use of a *template search path*, allowing template directories to be spread across different file-system locations. Using a @@ -159,6 +159,7 @@ See the `API documentation `_ for details on using Genshi via the Python API. +.. _`template loader`: loader.html .. _`expressions`: