Mercurial > genshi > genshi-test
comparison doc/loader.txt @ 902:09cc3627654c experimental-inline
Sync `experimental/inline` branch with [source:trunk@1126].
author | cmlenz |
---|---|
date | Fri, 23 Apr 2010 21:08:26 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
830:de82830f8816 | 902:09cc3627654c |
---|---|
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:: python | |
27 | |
28 from genshi.template import TemplateLoader | |
29 | |
30 loader = TemplateLoader(['/path/to/dir1', '/path/to/dir2'], | |
31 auto_reload=True) | |
32 tmpl = loader.load('test.html') | |
33 | |
34 When you try to load a template that can't be found, you get a | |
35 ``TemplateNotFound`` error. | |
36 | |
37 The default template class used by the loader is ``MarkupTemplate``, but that | |
38 can be overridden both with a different default (as a keyword argument to the | |
39 ``TemplateLoader`` constructor), as well as on invocation of the ``load()`` | |
40 method: | |
41 | |
42 .. code-block:: python | |
43 | |
44 from genshi.template.text import NewTextTemplate | |
45 | |
46 tmpl = loader.load('mail.txt', cls=NewTextTemplate) | |
47 | |
48 | |
49 ------- | |
50 Caching | |
51 ------- | |
52 | |
53 The ``TemplateLoader`` class provides a simple in-memory cache for parsed | |
54 template objects. This improves performance, because templates do not need to | |
55 be reparsed every time they are rendered. | |
56 | |
57 The size of this cache can be adjusted using the `max_cache_size` option on | |
58 the ``TemplateLoader`` constructor. The value of that option determines the | |
59 maximum number of template objects kept in the cache. When this limit is | |
60 reached, any templates that haven't been used in a while get purged. | |
61 Technically, this is a least-recently-used (LRU) cache, the default limit is | |
62 set to 25 templates. | |
63 | |
64 Automatic Reloading | |
65 =================== | |
66 | |
67 Once a template has been cached, it will normally not get reparsed until it | |
68 has been purged from the cache. This means that any changes to the template | |
69 file are not taken into consideration as long as it is still found in the | |
70 cache. As this is inconvenient in development scenarios, the ``auto_reload`` | |
71 option allows for automatic cache invalidation based on whether the template | |
72 source has changed. | |
73 | |
74 .. code-block:: python | |
75 | |
76 from genshi.template import TemplateLoader | |
77 | |
78 loader = TemplateLoader('templates', auto_reload=True, max_cache_size=100) | |
79 | |
80 In production environments, automatic reloading should be disabled, as it does | |
81 affect performance negatively. | |
82 | |
83 Callback Interface | |
84 ================== | |
85 | |
86 Sometimes you need to make sure that templates get properly configured after | |
87 they have been loaded, but you only want to do that when the template is | |
88 actually loaded and parsed, not when it is returned from the cache. | |
89 | |
90 For such cases, the ``TemplateLoader`` provides a way to specify a callback | |
91 function that gets invoked whenever a template is loaded. You can specify that | |
92 callback by passing it into the loader constructor via the ``callback`` | |
93 keyword argument, or later by setting the attribute of the same name. The | |
94 callback function should expect a single argument, the template object. | |
95 | |
96 For example, to properly inject the `translation filter`_ into any loaded | |
97 template, 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): | |
105 Translator(translations.ugettext).setup(template) | |
106 | |
107 loader = TemplateLoader('templates', callback=template_loaded) | |
108 | |
109 .. _`translation filter`: i18n.html | |
110 | |
111 -------------------- | |
112 Template Search Path | |
113 -------------------- | |
114 | |
115 The template loader can be configured with a list of multiple directories to | |
116 search for templates. The loader maps these directories to a single logical | |
117 directory for locating templates by file name. | |
118 | |
119 The order of the directories making up the search path is significant: the | |
120 loader will first try to locate a requested template in the first directory on | |
121 the path, then in the second, and so on. If there are two templates with the | |
122 same file name in multiple directories on the search path, whatever file is | |
123 found first gets used. | |
124 | |
125 Based on this design, an application could, for example, configure a search | |
126 path consisting of a directory containing the default templates, as well as a | |
127 directory where site-specific templates can be stored that will override the | |
128 default templates. | |
129 | |
130 | |
131 Load Functions | |
132 ============== | |
133 | |
134 Usually the search path consists of strings representing directory paths, but | |
135 it may also contain “load functions”: functions that are basically invoked | |
136 with the file name, and return the template content. | |
137 | |
138 Genshi comes with three builtin load functions: | |
139 | |
140 ``directory(path)`` | |
141 ------------------- | |
142 | |
143 The equivalent of just using a string containing the directory path: looks up | |
144 the file name in a specific directory. | |
145 | |
146 .. code-block:: python | |
147 | |
148 from genshi.template import TemplateLoader, loader | |
149 tl = TemplateLoader([loader.directory('/path/to/dir/')]) | |
150 | |
151 That is the same as: | |
152 | |
153 .. code-block:: python | |
154 | |
155 tl = TemplateLoader(['/path/to/dir/']) | |
156 | |
157 | |
158 ``package(name, path)`` | |
159 ----------------------- | |
160 | |
161 Uses the ``pkg_resources`` API to locate files in Python package data (which | |
162 may be inside a ZIP archive). | |
163 | |
164 .. code-block:: python | |
165 | |
166 from genshi.template import TemplateLoader, loader | |
167 tl = TemplateLoader([loader.package('myapp', 'templates')]) | |
168 | |
169 This will look for templates in the ``templates`` directory of the Python | |
170 package ``myapp``. | |
171 | |
172 ``prefixed(**delegates)`` | |
173 ------------------------- | |
174 | |
175 Delegates load requests to different load functions based on the path prefix. | |
176 | |
177 .. code-block:: python | |
178 | |
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') | |
186 | |
187 This example sets up a loader with three delegates, under the prefixes “core”, | |
188 “plugin1”, and “plugin2”. When a template is requested, the ``prefixed`` load | |
189 function looks for a delegate with a corresponding prefix, removes the prefix | |
190 from the path and asks the delegate to load the template. | |
191 | |
192 In 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 | |
194 other delegates are not checked as their prefix does not match. | |
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 | |
201 Custom Load Functions | |
202 --------------------- | |
203 | |
204 You can easily use your own load function with the template loader, for | |
205 example to load templates from a database. All that is needed is a callable | |
206 object that accepts a ``filename`` (a string) and returns a tuple of the form | |
207 ``(filepath, filename, fileobj, uptodate_fun)``, where: | |
208 | |
209 ``filepath`` | |
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. | |
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 | |
223 When the requested template can not be found, the function should raise an | |
224 ``IOError`` or ``TemplateNotFound`` exception. | |
225 | |
226 | |
227 ------------------ | |
228 Customized Loading | |
229 ------------------ | |
230 | |
231 If you require a completely different implementation of template loading, you | |
232 can extend or even replace the builtin ``TemplateLoader`` class. | |
233 | |
234 Protocol | |
235 ======== | |
236 | |
237 The protocol between the template loader and the ``Template`` class is simple | |
238 and only used for processing includes. The only required part of that protocol | |
239 is that the object assigned to ``Template.loader`` implements a ``load`` | |
240 method compatible to that of the ``TemplateLoader`` class, at the minimum with | |
241 the signature ``load(filename, relative_to=None, cls=None)``. | |
242 | |
243 In addition, templates currently check for the existence and value of a boolean | |
244 ``auto_reload`` property. If the property does not exist or evaluates to a | |
245 non-truth value, inlining of included templates is disabled. Inlining is a | |
246 small optimization that removes some overhead in the processing of includes. | |
247 | |
248 Subclassing ``TemplateLoader`` | |
249 ============================== | |
250 | |
251 You can also adjust the behavior of the ``TemplateLoader`` class by subclassing | |
252 it. 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 | |
254 the creation of the template object from the file name and content. Please | |
255 consult the code and the API documentation for more detail. |