Edgewall Software

source: trunk/doc/loader.txt

Last change on this file was 1113, checked in by cmlenz, 13 years ago

More doc tweaks.

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-rst
File size: 9.0 KB
RevLine 
[1106]1.. -*- mode: rst; encoding: utf-8 -*-
2
3=================
4Loading Templates
5=================
6
7Genshi comes with a simple but flexible implementation of a template loader in
8the ``genshi.template.loader`` module. The loader provides caching of
9templates so they do not need to be reparsed when used, support for multiple
10template directories that together form a virtual search path, as well as
11support for different template loading strategies.
12
13.. contents:: Contents
14   :depth: 3
15.. sectnum::
16
17
18-----
19Usage
20-----
21
22The basic usage pattern is simple: instantiate one ``TemplateLoader`` object
23and keep it around, then ask it to load a template whenever you need to load
24one:
25
[1107]26.. code-block:: python
[1106]27
[1107]28  from genshi.template import TemplateLoader
[1106]29 
[1107]30  loader = TemplateLoader(['/path/to/dir1', '/path/to/dir2'],
31                          auto_reload=True)
32  tmpl = loader.load('test.html')
[1106]33
34When you try to load a template that can't be found, you get a
[1107]35``TemplateNotFound`` error.
[1106]36
37The default template class used by the loader is ``MarkupTemplate``, but that
38can be overridden both with a different default (as a keyword argument to the
[1107]39``TemplateLoader`` constructor), as well as on invocation of the ``load()``
40method:
[1106]41
[1107]42.. code-block:: python
[1106]43
[1107]44  from genshi.template.text import NewTextTemplate
45 
46  tmpl = loader.load('mail.txt', cls=NewTextTemplate)
[1106]47
48
49-------
50Caching
51-------
52
53The ``TemplateLoader`` class provides a simple in-memory cache for parsed
54template objects. This improves performance, because templates do not need to
55be reparsed every time they are rendered.
56
57The size of this cache can be adjusted using the `max_cache_size` option on
58the ``TemplateLoader`` constructor. The value of that option determines the
59maximum number of template objects kept in the cache. When this limit is
60reached, any templates that haven't been used in a while get purged.
[1107]61Technically, this is a least-recently-used (LRU) cache, the default limit is
62set to 25 templates.
[1106]63
[1107]64Automatic Reloading
65===================
66
[1106]67Once a template has been cached, it will normally not get reparsed until it
68has been purged from the cache. This means that any changes to the template
[1107]69file are not taken into consideration as long as it is still found in the
[1106]70cache. As this is inconvenient in development scenarios, the ``auto_reload``
71option allows for automatic cache invalidation based on whether the template
[1107]72source has changed.
[1106]73
[1107]74.. code-block:: python
[1106]75
[1107]76  from genshi.template import TemplateLoader
77 
78  loader = TemplateLoader('templates', auto_reload=True, max_cache_size=100)
79
80In production environments, automatic reloading should be disabled, as it does
81affect performance negatively.
82
83Callback Interface
84==================
85
86Sometimes you need to make sure that templates get properly configured after
87they have been loaded, but you only want to do that when the template is
88actually loaded and parsed, not when it is returned from the cache.
89
90For such cases, the ``TemplateLoader`` provides a way to specify a callback
91function that gets invoked whenever a template is loaded. You can specify that
92callback by passing it into the loader constructor via the ``callback``
93keyword argument, or later by setting the attribute of the same name. The
94callback function should expect a single argument, the template object.
95
96For example, to properly inject the `translation filter`_ into any loaded
97template, you'd use code similar to this:
98
99.. code-block:: python
100
101  from genshi.filters import Translator
102  from genshi.template import TemplateLoader
103 
104  def template_loaded(template):
[1108]105      Translator(translations.ugettext).setup(template)
[1107]106 
107  loader = TemplateLoader('templates', callback=template_loaded)
108
109.. _`translation filter`: i18n.html
110
[1106]111--------------------
112Template Search Path
113--------------------
114
[1107]115The template loader can be configured with a list of multiple directories to
116search for templates. The loader maps these directories to a single logical
117directory for locating templates by file name.
[1106]118
119The order of the directories making up the search path is significant: the
[1107]120loader will first try to locate a requested template in the first directory on
121the path, then in the second, and so on. If there are two templates with the
122same file name in multiple directories on the search path, whatever file is
123found first gets used.
[1106]124
125Based on this design, an application could, for example, configure a search
126path consisting of a directory containing the default templates, as well as a
127directory where site-specific templates can be stored that will override the
128default templates.
129
130
131Load Functions
132==============
133
134Usually the search path consists of strings representing directory paths, but
135it may also contain “load functions”: functions that are basically invoked
136with the file name, and return the template content.
137
138Genshi comes with three builtin load functions:
139
140``directory(path)``
141-------------------
142
143The equivalent of just using a string containing the directory path: looks up
144the file name in a specific directory.
145
[1107]146.. code-block:: python
[1106]147
[1107]148  from genshi.template import TemplateLoader, loader
149  tl = TemplateLoader([loader.directory('/path/to/dir/')])
[1106]150
151That is the same as:
152
[1107]153.. code-block:: python
[1106]154
[1107]155  tl = TemplateLoader(['/path/to/dir/'])
[1106]156
157
158``package(name, path)``
159-----------------------
160
161Uses the ``pkg_resources`` API to locate files in Python package data (which
162may be inside a ZIP archive).
163
[1107]164.. code-block:: python
[1106]165
[1107]166  from genshi.template import TemplateLoader, loader
167  tl = TemplateLoader([loader.package('myapp', 'templates')])
[1106]168
169This will look for templates in the ``templates`` directory of the Python
170package ``myapp``.
171
172``prefixed(**delegates)``
173-------------------------
174
175Delegates load requests to different load functions based on the path prefix.
176
[1107]177.. code-block:: python
[1106]178
[1107]179  from genshi.template import TemplateLoader, loader
180  tl = TemplateLoader(loader.prefixed(
181    core = '/tmp/dir1',
182    plugin1 = loader.package('plugin1', 'templates'),
183    plugin2 = loader.package('plugin2', 'templates'),
184  ))
185  tmpl = tl.load('core/index.html')
[1106]186
187This example sets up a loader with three delegates, under the prefixes “core”,
[1107]188“plugin1”, and “plugin2”. When a template is requested, the ``prefixed`` load
[1106]189function looks for a delegate with a corresponding prefix, removes the prefix
190from the path and asks the delegate to load the template.
191
192In this case, assuming the directory ``/path/to/dir`` contains a file named
193``index.html``, that file will be used when we load ``core/index.html``. The
[1107]194other delegates are not checked as their prefix does not match.
[1106]195
196
197.. note:: These builtin load functions are available both as class methods
198          of the ``TemplateLoader`` class as well as on the module level
199
200
201Custom Load Functions
202---------------------
203
204You can easily use your own load function with the template loader, for
205example to load templates from a database. All that is needed is a callable
206object that accepts a ``filename`` (a string) and returns a tuple of the form
207``(filepath, filename, fileobj, uptodate_fun)``, where:
208
209``filepath``
[1107]210  is the absolute path to the template. This is primarily used for output in
211  tracebacks, and does not need to map to an actual path on the file system.
[1106]212``filename``
213  is the base name of the template file
214``fileobj``
215  is a readable file-like object that provides the content of the template
216``uptodate_fun``
217  is a function that the loader can invoke to check whether the cached version
218  of the template is still up-to-date, or ``None`` if the load function is not
219  able to provide such a check. If provided, the function should not expect
220  any parameters (so you'll definitely want to use a closure here), and should
221  return ``True`` if the template has not changed since it was last loaded.
222
223When the requested template can not be found, the function should raise an
224``IOError`` or ``TemplateNotFound`` exception.
225
226
227------------------
228Customized Loading
229------------------
230
231If you require a completely different implementation of template loading, you
232can extend or even replace the builtin ``TemplateLoader`` class.
233
234Protocol
235========
236
[1107]237The protocol between the template loader and the ``Template`` class is simple
[1106]238and only used for processing includes. The only required part of that protocol
239is that the object assigned to ``Template.loader`` implements a ``load``
240method compatible to that of the ``TemplateLoader`` class, at the minimum with
241the signature ``load(filename, relative_to=None, cls=None)``.
242
243In addition, templates currently check for the existence and value of a boolean
[1113]244``auto_reload`` property. If the property does not exist or evaluates to a
245non-truth value, inlining of included templates is disabled. Inlining is a
246small optimization that removes some overhead in the processing of includes.
[1106]247
248Subclassing ``TemplateLoader``
249==============================
250
251You can also adjust the behavior of the ``TemplateLoader`` class by subclassing
252it. You can of course override anything needed, but the class also provides the
253``_instantiate()`` hook, which is intended for use by subclasses to customize
254the creation of the template object from the file name and content. Please
255consult the code and the API documentation for more detail.
Note: See TracBrowser for help on using the repository browser.