Mercurial > genshi > genshi-test
annotate doc/templates.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 | 1837f39efd6f |
children |
rev | line source |
---|---|
500 | 1 .. -*- mode: rst; encoding: utf-8 -*- |
2 | |
3 ======================== | |
4 Genshi Templating Basics | |
5 ======================== | |
6 | |
7 Genshi provides a template engine that can be used for generating either | |
8 markup (such as HTML_ or XML_) or plain text. While both share some of the | |
9 syntax (and much of the underlying implementation) they are essentially | |
10 separate languages. | |
11 | |
12 .. _html: http://www.w3.org/html/ | |
13 .. _xml: http://www.w3.org/XML/ | |
14 | |
15 This document describes the common parts of the template engine and will be most | |
16 useful as reference to those developing Genshi templates. Templates are XML or | |
17 plain text files that include processing directives_ that affect how the | |
18 template is rendered, and template expressions_ that are dynamically substituted | |
19 by variable data. | |
20 | |
21 | |
22 .. contents:: Contents | |
23 :depth: 3 | |
24 .. sectnum:: | |
25 | |
26 -------- | |
27 Synopsis | |
28 -------- | |
29 | |
30 A Genshi *markup template* is a well-formed XML document with embedded Python | |
31 used for control flow and variable substitution. Markup templates should be | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
32 used to generate any kind of HTML or XML output, as they provide a number of |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
33 advantages over simple text-based templates (such as automatic escaping of |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
34 variable data). |
500 | 35 |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
36 The following is a simple Genshi markup template: |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
37 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
38 .. code-block:: genshi |
500 | 39 |
40 <?python | |
41 title = "A Genshi Template" | |
42 fruits = ["apple", "orange", "kiwi"] | |
43 ?> | |
44 <html xmlns:py="http://genshi.edgewall.org/"> | |
45 <head> | |
46 <title py:content="title">This is replaced.</title> | |
47 </head> | |
48 | |
49 <body> | |
50 <p>These are some of my favorite fruits:</p> | |
51 <ul> | |
52 <li py:for="fruit in fruits"> | |
53 I like ${fruit}s | |
54 </li> | |
55 </ul> | |
56 </body> | |
57 </html> | |
58 | |
59 This example shows: | |
60 | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
61 (a) a Python code block in a processing instruction |
500 | 62 (b) the Genshi namespace declaration |
63 (c) usage of templates directives (``py:content`` and ``py:for``) | |
64 (d) an inline Python expression (``${fruit}``). | |
65 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
66 The template would generate output similar to this: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
67 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
68 .. code-block:: genshi |
500 | 69 |
70 <html> | |
71 <head> | |
72 <title>A Genshi Template</title> | |
73 </head> | |
74 | |
75 <body> | |
76 <p>These are some of my favorite fruits:</p> | |
77 <ul> | |
78 <li>I like apples</li> | |
79 <li>I like oranges</li> | |
80 <li>I like kiwis</li> | |
81 </ul> | |
82 </body> | |
83 </html> | |
84 | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
85 A *text template* is a simple plain text document that can also contain |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
86 embedded Python code. Text templates are intended to be used for simple |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
87 *non-markup* text formats, such as the body of an plain text email. For |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
88 example: |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
89 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
90 .. code-block:: genshitext |
500 | 91 |
92 Dear $name, | |
93 | |
94 These are some of my favorite fruits: | |
95 #for fruit in fruits | |
96 * $fruit | |
97 #end | |
98 | |
99 | |
100 ---------- | |
101 Python API | |
102 ---------- | |
103 | |
104 The Python code required for templating with Genshi is generally based on the | |
105 following pattern: | |
106 | |
107 * Attain a ``MarkupTemplate`` or ``TextTemplate`` object from a string or | |
108 file-like object containing the template source. This can either be done | |
109 directly, or through a ``TemplateLoader`` instance. | |
110 * Call the ``generate()`` method of the template, passing any data that should | |
111 be made available to the template as keyword arguments. | |
112 * Serialize the resulting stream using its ``render()`` method. | |
113 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
114 For example: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
115 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
116 .. code-block:: pycon |
500 | 117 |
118 >>> from genshi.template import MarkupTemplate | |
119 >>> tmpl = MarkupTemplate('<h1>Hello, $name!</h1>') | |
120 >>> stream = tmpl.generate(name='world') | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
121 >>> print(stream.render('xhtml')) |
500 | 122 <h1>Hello, world!</h1> |
123 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
124 .. note:: See the Serialization_ section of the `Markup Streams`_ page for |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
125 information on configuring template output options. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
126 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
127 Using a text template is similar: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
128 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
129 .. code-block:: pycon |
500 | 130 |
131 >>> from genshi.template import TextTemplate | |
132 >>> tmpl = TextTemplate('Hello, $name!') | |
133 >>> stream = tmpl.generate(name='world') | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
134 >>> print(stream) |
500 | 135 Hello, world! |
136 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
137 .. note:: If you want to use text templates, you should consider using the |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
138 ``NewTextTemplate`` class instead of simply ``TextTemplate``. See |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
139 the `Text Template Language`_ page. |
500 | 140 |
141 .. _serialization: streams.html#serialization | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
142 .. _`Text Template Language`: text-templates.html |
500 | 143 .. _`Markup Streams`: streams.html |
144 | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
145 Using a `template loader`_ provides the advantage that “compiled” templates are |
500 | 146 automatically cached, and only parsed again when the template file changes. In |
147 addition, it enables the use of a *template search path*, allowing template | |
148 directories to be spread across different file-system locations. Using a | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
149 template loader would generally look as follows: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
150 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
151 .. code-block:: python |
500 | 152 |
153 from genshi.template import TemplateLoader | |
154 loader = TemplateLoader([templates_dir1, templates_dir2]) | |
155 tmpl = loader.load('test.html') | |
156 stream = tmpl.generate(title='Hello, world!') | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
157 print(stream.render()) |
500 | 158 |
159 See the `API documentation <api/index.html>`_ for details on using Genshi via | |
160 the Python API. | |
161 | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
162 .. _`template loader`: loader.html |
500 | 163 |
164 .. _`expressions`: | |
165 | |
166 ------------------------------------ | |
167 Template Expressions and Code Blocks | |
168 ------------------------------------ | |
169 | |
170 Python_ expressions can be used in text and directive arguments. An expression | |
171 is substituted with the result of its evaluation against the template data. | |
172 Expressions in text (which includes the values of non-directive attributes) need | |
173 to prefixed with a dollar sign (``$``) and usually enclosed in curly braces | |
174 (``{…}``). | |
175 | |
176 .. _python: http://www.python.org/ | |
177 | |
178 If the expression starts with a letter and contains only letters, digits, dots, | |
179 and underscores, the curly braces may be omitted. In all other cases, the | |
180 braces are required so that the template processor knows where the expression | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
181 ends: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
182 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
183 .. code-block:: pycon |
500 | 184 |
185 >>> from genshi.template import MarkupTemplate | |
186 >>> tmpl = MarkupTemplate('<em>${items[0].capitalize()} item</em>') | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
187 >>> print(tmpl.generate(items=['first', 'second'])) |
500 | 188 <em>First item</em> |
189 | |
190 Expressions support the full power of Python. In addition, it is possible to | |
191 access items in a dictionary using “dotted notation” (i.e. as if they were | |
192 attributes), and vice-versa (i.e. access attributes as if they were items in a | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
193 dictionary): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
194 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
195 .. code-block:: pycon |
500 | 196 |
197 >>> from genshi.template import MarkupTemplate | |
198 >>> tmpl = MarkupTemplate('<em>${dict.foo}</em>') | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
199 >>> print(tmpl.generate(dict={'foo': 'bar'})) |
500 | 200 <em>bar</em> |
201 | |
202 Because there are two ways to access either attributes or items, expressions | |
203 do not raise the standard ``AttributeError`` or ``IndexError`` exceptions, but | |
204 rather an exception of the type ``UndefinedError``. The same kind of error is | |
205 raised when you try to use a top-level variable that is not in the context data. | |
206 See `Error Handling`_ below for details on how such errors are handled. | |
207 | |
208 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
209 Escaping |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
210 ======== |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
211 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
212 If you need to include a literal dollar sign in the output where Genshi would |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
213 normally detect an expression, you can simply add another dollar sign: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
214 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
215 .. code-block:: pycon |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
216 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
217 >>> from genshi.template import MarkupTemplate |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
218 >>> tmpl = MarkupTemplate('<em>$foo</em>') # Wanted "$foo" as literal output |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
219 >>> print(tmpl.generate()) |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
220 Traceback (most recent call last): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
221 ... |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
222 UndefinedError: "foo" not defined |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
223 >>> tmpl = MarkupTemplate('<em>$$foo</em>') |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
224 >>> print(tmpl.generate()) |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
225 <em>$foo</em> |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
226 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
227 But note that this is not necessary if the characters following the dollar sign |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
228 do not qualify as an expression. For example, the following needs no escaping: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
229 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
230 .. code-block:: pycon |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
231 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
232 >>> tmpl = MarkupTemplate('<script>$(function() {})</script>') |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
233 >>> print(tmpl.generate()) |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
234 <script>$(function() {})</script> |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
235 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
236 On the other hand, Genshi will always replace two dollar signs in text with a |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
237 single dollar sign, so you'll need to use three dollar signs to get two in the |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
238 output: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
239 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
240 .. code-block:: pycon |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
241 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
242 >>> tmpl = MarkupTemplate('<script>$$$("div")</script>') |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
243 >>> print(tmpl.generate()) |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
244 <script>$$("div")</script> |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
245 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
246 |
500 | 247 .. _`code blocks`: |
248 | |
249 Code Blocks | |
250 =========== | |
251 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
252 Templates also support full Python code blocks, using the ``<?python ?>`` |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
253 processing instruction in XML templates: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
254 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
255 .. code-block:: genshi |
500 | 256 |
257 <div> | |
258 <?python | |
259 from genshi.builder import tag | |
260 def greeting(name): | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
261 return tag.b('Hello, %s!' % name) ?> |
500 | 262 ${greeting('world')} |
263 </div> | |
264 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
265 This will produce the following output: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
266 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
267 .. code-block:: xml |
500 | 268 |
269 <div> | |
270 <b>Hello, world!</b> | |
271 </div> | |
272 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
273 In text templates (although only those using the new syntax introduced in |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
274 Genshi 0.5), code blocks use the special ``{% python %}`` directive: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
275 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
276 .. code-block:: genshitext |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
277 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
278 {% python |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
279 from genshi.builder import tag |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
280 def greeting(name): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
281 return 'Hello, %s!' % name |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
282 %} |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
283 ${greeting('world')} |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
284 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
285 This will produce the following output:: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
286 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
287 Hello, world! |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
288 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
289 |
500 | 290 Code blocks can import modules, define classes and functions, and basically do |
291 anything you can do in normal Python code. What code blocks can *not* do is to | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
292 produce content that is emitted directly tp the generated output. |
500 | 293 |
294 .. note:: Using the ``print`` statement will print to the standard output | |
295 stream, just as it does for other Python code in your application. | |
296 | |
297 Unlike expressions, Python code in ``<?python ?>`` processing instructions can | |
298 not use item and attribute access in an interchangeable manner. That means that | |
299 “dotted notation” is always attribute access, and vice-versa. | |
300 | |
301 The support for Python code blocks in templates is not supposed to encourage | |
302 mixing application code into templates, which is generally considered bad | |
303 design. If you're using many code blocks, that may be a sign that you should | |
304 move such code into separate Python modules. | |
305 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
306 If you'd rather not allow the use of Python code blocks in templates, you can |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
307 simply set the ``allow_exec`` parameter (available on the ``Template`` and the |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
308 ``TemplateLoader`` initializers) to ``False``. In that case Genshi will raise |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
309 a syntax error when a ``<?python ?>`` processing instruction is encountered. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
310 But please note that disallowing code blocks in templates does not turn Genshi |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
311 into a sandboxable template engine; there are sufficient ways to do harm even |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
312 using plain expressions. |
500 | 313 |
314 | |
315 .. _`error handling`: | |
316 | |
317 Error Handling | |
318 ============== | |
319 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
320 By default, Genshi raises an ``UndefinedError`` if a template expression |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
321 attempts to access a variable that is not defined: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
322 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
323 .. code-block:: pycon |
500 | 324 |
325 >>> from genshi.template import MarkupTemplate | |
326 >>> tmpl = MarkupTemplate('<p>${doh}</p>') | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
327 >>> tmpl.generate().render('xhtml') |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
328 Traceback (most recent call last): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
329 ... |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
330 UndefinedError: "doh" not defined |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
331 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
332 You can change this behavior by setting the variable lookup mode to "lenient". |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
333 In that case, accessing undefined variables returns an `Undefined` object, |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
334 meaning that the expression does not fail immediately. See below for details. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
335 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
336 If you need to check whether a variable exists in the template context, use the |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
337 defined_ or the value_of_ function described below. To check for existence of |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
338 attributes on an object, or keys in a dictionary, use the ``hasattr()``, |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
339 ``getattr()`` or ``get()`` functions, or the ``in`` operator, just as you would |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
340 in regular Python code: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
341 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
342 >>> from genshi.template import MarkupTemplate |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
343 >>> tmpl = MarkupTemplate('<p>${defined("doh")}</p>') |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
344 >>> print(tmpl.generate().render('xhtml')) |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
345 <p>False</p> |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
346 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
347 .. note:: Lenient error handling was the default in Genshi prior to version 0.5. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
348 Strict mode was introduced in version 0.4, and became the default in |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
349 0.5. The reason for this change was that the lenient error handling |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
350 was masking actual errors in templates, thereby also making it harder |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
351 to debug some problems. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
352 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
353 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
354 .. _`lenient`: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
355 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
356 Lenient Mode |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
357 ------------ |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
358 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
359 If you instruct Genshi to use the lenient variable lookup mode, it allows you |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
360 to access variables that are not defined, without raising an ``UndefinedError``. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
361 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
362 This mode can be chosen by passing the ``lookup='lenient'`` keyword argument to |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
363 the template initializer, or by passing the ``variable_lookup='lenient'`` |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
364 keyword argument to the ``TemplateLoader`` initializer: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
365 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
366 .. code-block:: pycon |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
367 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
368 >>> from genshi.template import MarkupTemplate |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
369 >>> tmpl = MarkupTemplate('<p>${doh}</p>', lookup='lenient') |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
370 >>> print(tmpl.generate().render('xhtml')) |
500 | 371 <p></p> |
372 | |
373 You *will* however get an exception if you try to call an undefined variable, or | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
374 do anything else with it, such as accessing its attributes: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
375 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
376 .. code-block:: pycon |
500 | 377 |
378 >>> from genshi.template import MarkupTemplate | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
379 >>> tmpl = MarkupTemplate('<p>${doh.oops}</p>', lookup='lenient') |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
380 >>> print(tmpl.generate().render('xhtml')) |
500 | 381 Traceback (most recent call last): |
382 ... | |
383 UndefinedError: "doh" not defined | |
384 | |
385 If you need to know whether a variable is defined, you can check its type | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
386 against the ``Undefined`` class, for example in a conditional directive: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
387 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
388 .. code-block:: pycon |
500 | 389 |
390 >>> from genshi.template import MarkupTemplate | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
391 >>> tmpl = MarkupTemplate('<p>${type(doh) is not Undefined}</p>', |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
392 ... lookup='lenient') |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
820
diff
changeset
|
393 >>> print(tmpl.generate().render('xhtml')) |
500 | 394 <p>False</p> |
395 | |
396 Alternatively, the built-in functions defined_ or value_of_ can be used in this | |
397 case. | |
398 | |
399 Custom Modes | |
400 ------------ | |
401 | |
402 In addition to the built-in "lenient" and "strict" modes, it is also possible to | |
403 use a custom error handling mode. For example, you could use lenient error | |
404 handling in a production environment, while also logging a warning when an | |
405 undefined variable is referenced. | |
406 | |
407 See the API documentation of the ``genshi.template.eval`` module for details. | |
408 | |
409 | |
410 Built-in Functions & Types | |
411 ========================== | |
412 | |
413 The following functions and types are available by default in template code, in | |
414 addition to the standard built-ins that are available to all Python code. | |
415 | |
416 .. _`defined`: | |
417 | |
418 ``defined(name)`` | |
419 ----------------- | |
420 This function determines whether a variable of the specified name exists in | |
421 the context data, and returns ``True`` if it does. | |
422 | |
423 .. _`value_of`: | |
424 | |
425 ``value_of(name, default=None)`` | |
426 -------------------------------- | |
427 This function returns the value of the variable with the specified name if | |
428 such a variable is defined, and returns the value of the ``default`` | |
429 parameter if no such variable is defined. | |
430 | |
431 .. _`Markup`: | |
432 | |
433 ``Markup(text)`` | |
434 ---------------- | |
435 The ``Markup`` type marks a given string as being safe for inclusion in markup, | |
436 meaning it will *not* be escaped in the serialization stage. Use this with care, | |
437 as not escaping a user-provided string may allow malicious users to open your | |
438 web site to cross-site scripting attacks. | |
439 | |
440 .. _`Undefined`: | |
441 | |
442 ``Undefined`` | |
443 ---------------- | |
444 The ``Undefined`` type can be used to check whether a reference variable is | |
445 defined, as explained in `error handling`_. | |
446 | |
447 | |
448 .. _`directives`: | |
449 | |
450 ------------------- | |
451 Template Directives | |
452 ------------------- | |
453 | |
454 Directives provide control flow functionality for templates, such as conditions | |
455 or iteration. As the syntax for directives depends on whether you're using | |
456 markup or text templates, refer to the | |
457 `XML Template Language <xml-templates.html>`_ or | |
458 `Text Template Language <text-templates.html>`_ pages for information. |