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