Mercurial > genshi > genshi-test
annotate genshi/template/base.py @ 902:09cc3627654c experimental-inline
Sync `experimental/inline` branch with [source:trunk@1126].
author | cmlenz |
---|---|
date | Fri, 23 Apr 2010 21:08:26 +0000 |
parents | de82830f8816 |
children |
rev | line source |
---|---|
500 | 1 # -*- coding: utf-8 -*- |
2 # | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
3 # Copyright (C) 2006-2010 Edgewall Software |
500 | 4 # All rights reserved. |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
8 # are also available at http://genshi.edgewall.org/wiki/License. | |
9 # | |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
12 # history and logs, available at http://genshi.edgewall.org/log/. | |
13 | |
14 """Basic templating functionality.""" | |
15 | |
830 | 16 from collections import deque |
500 | 17 import os |
18 from StringIO import StringIO | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
19 import sys |
828
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
20 from types import ModuleType |
500 | 21 |
22 from genshi.core import Attrs, Stream, StreamEventKind, START, TEXT, _ensure | |
23 from genshi.input import ParseError | |
24 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
25 __all__ = ['Context', 'DirectiveFactory', 'Template', 'TemplateError', |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
26 'TemplateRuntimeError', 'TemplateSyntaxError', 'BadDirectiveError'] |
500 | 27 __docformat__ = 'restructuredtext en' |
28 | |
29 | |
30 class TemplateError(Exception): | |
31 """Base exception class for errors related to template processing.""" | |
32 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
33 def __init__(self, message, filename=None, lineno=-1, offset=-1): |
500 | 34 """Create the exception. |
35 | |
36 :param message: the error message | |
37 :param filename: the filename of the template | |
38 :param lineno: the number of line in the template at which the error | |
39 occurred | |
40 :param offset: the column number at which the error occurred | |
41 """ | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
42 if filename is None: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
43 filename = '<string>' |
500 | 44 self.msg = message #: the error message string |
45 if filename != '<string>' or lineno >= 0: | |
46 message = '%s (%s, line %d)' % (self.msg, filename, lineno) | |
47 Exception.__init__(self, message) | |
48 self.filename = filename #: the name of the template file | |
49 self.lineno = lineno #: the number of the line containing the error | |
50 self.offset = offset #: the offset on the line | |
51 | |
52 | |
53 class TemplateSyntaxError(TemplateError): | |
54 """Exception raised when an expression in a template causes a Python syntax | |
55 error, or the template is not well-formed. | |
56 """ | |
57 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
58 def __init__(self, message, filename=None, lineno=-1, offset=-1): |
500 | 59 """Create the exception |
60 | |
61 :param message: the error message | |
62 :param filename: the filename of the template | |
63 :param lineno: the number of line in the template at which the error | |
64 occurred | |
65 :param offset: the column number at which the error occurred | |
66 """ | |
67 if isinstance(message, SyntaxError) and message.lineno is not None: | |
68 message = str(message).replace(' (line %d)' % message.lineno, '') | |
69 TemplateError.__init__(self, message, filename, lineno) | |
70 | |
71 | |
72 class BadDirectiveError(TemplateSyntaxError): | |
73 """Exception raised when an unknown directive is encountered when parsing | |
74 a template. | |
75 | |
76 An unknown directive is any attribute using the namespace for directives, | |
77 with a local name that doesn't match any registered directive. | |
78 """ | |
79 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
80 def __init__(self, name, filename=None, lineno=-1): |
500 | 81 """Create the exception |
82 | |
83 :param name: the name of the directive | |
84 :param filename: the filename of the template | |
85 :param lineno: the number of line in the template at which the error | |
86 occurred | |
87 """ | |
88 TemplateSyntaxError.__init__(self, 'bad directive "%s"' % name, | |
89 filename, lineno) | |
90 | |
91 | |
92 class TemplateRuntimeError(TemplateError): | |
93 """Exception raised when an the evaluation of a Python expression in a | |
94 template causes an error. | |
95 """ | |
96 | |
97 | |
98 class Context(object): | |
99 """Container for template input data. | |
100 | |
101 A context provides a stack of scopes (represented by dictionaries). | |
102 | |
103 Template directives such as loops can push a new scope on the stack with | |
104 data that should only be available inside the loop. When the loop | |
105 terminates, that scope can get popped off the stack again. | |
106 | |
107 >>> ctxt = Context(one='foo', other=1) | |
108 >>> ctxt.get('one') | |
109 'foo' | |
110 >>> ctxt.get('other') | |
111 1 | |
112 >>> ctxt.push(dict(one='frost')) | |
113 >>> ctxt.get('one') | |
114 'frost' | |
115 >>> ctxt.get('other') | |
116 1 | |
117 >>> ctxt.pop() | |
118 {'one': 'frost'} | |
119 >>> ctxt.get('one') | |
120 'foo' | |
121 """ | |
122 | |
123 def __init__(self, **data): | |
124 """Initialize the template context with the given keyword arguments as | |
125 data. | |
126 """ | |
127 self.frames = deque([data]) | |
128 self.pop = self.frames.popleft | |
129 self.push = self.frames.appendleft | |
130 self._match_templates = [] | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
131 self._choice_stack = [] |
500 | 132 |
133 # Helper functions for use in expressions | |
134 def defined(name): | |
135 """Return whether a variable with the specified name exists in the | |
136 expression scope.""" | |
137 return name in self | |
138 def value_of(name, default=None): | |
139 """If a variable of the specified name is defined, return its value. | |
140 Otherwise, return the provided default value, or ``None``.""" | |
141 return self.get(name, default) | |
142 data.setdefault('defined', defined) | |
143 data.setdefault('value_of', value_of) | |
144 | |
145 def __repr__(self): | |
146 return repr(list(self.frames)) | |
147 | |
148 def __contains__(self, key): | |
149 """Return whether a variable exists in any of the scopes. | |
150 | |
151 :param key: the name of the variable | |
152 """ | |
153 return self._find(key)[1] is not None | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
154 has_key = __contains__ |
500 | 155 |
156 def __delitem__(self, key): | |
157 """Remove a variable from all scopes. | |
158 | |
159 :param key: the name of the variable | |
160 """ | |
161 for frame in self.frames: | |
162 if key in frame: | |
163 del frame[key] | |
164 | |
165 def __getitem__(self, key): | |
166 """Get a variables's value, starting at the current scope and going | |
167 upward. | |
168 | |
169 :param key: the name of the variable | |
170 :return: the variable value | |
171 :raises KeyError: if the requested variable wasn't found in any scope | |
172 """ | |
173 value, frame = self._find(key) | |
174 if frame is None: | |
175 raise KeyError(key) | |
176 return value | |
177 | |
178 def __len__(self): | |
179 """Return the number of distinctly named variables in the context. | |
180 | |
181 :return: the number of variables in the context | |
182 """ | |
183 return len(self.items()) | |
184 | |
185 def __setitem__(self, key, value): | |
186 """Set a variable in the current scope. | |
187 | |
188 :param key: the name of the variable | |
189 :param value: the variable value | |
190 """ | |
191 self.frames[0][key] = value | |
192 | |
193 def _find(self, key, default=None): | |
194 """Retrieve a given variable's value and the frame it was found in. | |
195 | |
196 Intended primarily for internal use by directives. | |
197 | |
198 :param key: the name of the variable | |
199 :param default: the default value to return when the variable is not | |
200 found | |
201 """ | |
202 for frame in self.frames: | |
203 if key in frame: | |
204 return frame[key], frame | |
205 return default, None | |
206 | |
207 def get(self, key, default=None): | |
208 """Get a variable's value, starting at the current scope and going | |
209 upward. | |
210 | |
211 :param key: the name of the variable | |
212 :param default: the default value to return when the variable is not | |
213 found | |
214 """ | |
215 for frame in self.frames: | |
216 if key in frame: | |
217 return frame[key] | |
218 return default | |
219 | |
220 def keys(self): | |
221 """Return the name of all variables in the context. | |
222 | |
223 :return: a list of variable names | |
224 """ | |
225 keys = [] | |
226 for frame in self.frames: | |
227 keys += [key for key in frame if key not in keys] | |
228 return keys | |
229 | |
230 def items(self): | |
231 """Return a list of ``(name, value)`` tuples for all variables in the | |
232 context. | |
233 | |
234 :return: a list of variables | |
235 """ | |
236 return [(key, self.get(key)) for key in self.keys()] | |
237 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
238 def update(self, mapping): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
239 """Update the context from the mapping provided.""" |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
240 self.frames[0].update(mapping) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
241 |
500 | 242 def push(self, data): |
243 """Push a new scope on the stack. | |
244 | |
245 :param data: the data dictionary to push on the context stack. | |
246 """ | |
247 | |
248 def pop(self): | |
249 """Pop the top-most scope from the stack.""" | |
250 | |
251 | |
830 | 252 def _apply_directives(stream, directives, ctxt, vars): |
500 | 253 """Apply the given directives to the stream. |
254 | |
255 :param stream: the stream the directives should be applied to | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
256 :param directives: the list of directives to apply |
500 | 257 :param ctxt: the `Context` |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
258 :param vars: additional variables that should be available when Python |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
259 code is executed |
500 | 260 :return: the stream with the given directives applied |
261 """ | |
262 if directives: | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
263 stream = directives[0](iter(stream), directives[1:], ctxt, **vars) |
500 | 264 return stream |
265 | |
830 | 266 |
267 def _eval_expr(expr, ctxt, vars=None): | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
268 """Evaluate the given `Expression` object. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
269 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
270 :param expr: the expression to evaluate |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
271 :param ctxt: the `Context` |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
272 :param vars: additional variables that should be available to the |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
273 expression |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
274 :return: the result of the evaluation |
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 if vars: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
277 ctxt.push(vars) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
278 retval = expr.evaluate(ctxt) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
279 if vars: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
280 ctxt.pop() |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
281 return retval |
500 | 282 |
830 | 283 |
284 def _exec_suite(suite, ctxt, vars=None): | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
285 """Execute the given `Suite` object. |
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 :param suite: the code suite to execute |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
288 :param ctxt: the `Context` |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
289 :param vars: additional variables that should be available to the |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
290 code |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
291 """ |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
292 if vars: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
293 ctxt.push(vars) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
294 ctxt.push({}) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
295 suite.execute(ctxt) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
296 if vars: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
297 top = ctxt.pop() |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
298 ctxt.pop() |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
299 ctxt.frames[0].update(top) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
300 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
301 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
302 class DirectiveFactoryMeta(type): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
303 """Meta class for directive factories.""" |
500 | 304 |
305 def __new__(cls, name, bases, d): | |
306 if 'directives' in d: | |
307 d['_dir_by_name'] = dict(d['directives']) | |
308 d['_dir_order'] = [directive[1] for directive in d['directives']] | |
309 | |
310 return type.__new__(cls, name, bases, d) | |
311 | |
312 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
313 class DirectiveFactory(object): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
314 """Base for classes that provide a set of template directives. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
315 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
316 :since: version 0.6 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
317 """ |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
318 __metaclass__ = DirectiveFactoryMeta |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
319 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
320 directives = [] |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
321 """A list of ``(name, cls)`` tuples that define the set of directives |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
322 provided by this factory. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
323 """ |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
324 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
325 def get_directive(self, name): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
326 """Return the directive class for the given name. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
327 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
328 :param name: the directive name as used in the template |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
329 :return: the directive class |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
330 :see: `Directive` |
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 return self._dir_by_name.get(name) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
333 |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
334 def get_directive_index(self, dir_cls): |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
335 """Return a key for the given directive class that should be used to |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
336 sort it among other directives on the same `SUB` event. |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
337 |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
338 The default implementation simply returns the index of the directive in |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
339 the `directives` list. |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
340 |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
341 :param dir_cls: the directive class |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
342 :return: the sort key |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
343 """ |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
344 if dir_cls in self._dir_order: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
345 return self._dir_order.index(dir_cls) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
346 return len(self._dir_order) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
347 |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
348 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
349 class Template(DirectiveFactory): |
500 | 350 """Abstract template base class. |
351 | |
352 This class implements most of the template processing model, but does not | |
353 specify the syntax of templates. | |
354 """ | |
820
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 EXEC = StreamEventKind('EXEC') |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
357 """Stream event kind representing a Python code suite to execute.""" |
500 | 358 |
359 EXPR = StreamEventKind('EXPR') | |
360 """Stream event kind representing a Python expression.""" | |
361 | |
362 INCLUDE = StreamEventKind('INCLUDE') | |
363 """Stream event kind representing the inclusion of another template.""" | |
364 | |
365 SUB = StreamEventKind('SUB') | |
366 """Stream event kind representing a nested stream to which one or more | |
367 directives should be applied. | |
368 """ | |
369 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
370 serializer = None |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
371 _number_conv = unicode # function used to convert numbers to event data |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
372 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
373 def __init__(self, source, filepath=None, filename=None, loader=None, |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
374 encoding=None, lookup='strict', allow_exec=True): |
500 | 375 """Initialize a template from either a string, a file-like object, or |
376 an already parsed markup stream. | |
377 | |
378 :param source: a string, file-like object, or markup stream to read the | |
379 template from | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
380 :param filepath: the absolute path to the template file |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
381 :param filename: the path to the template file relative to the search |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
382 path |
500 | 383 :param loader: the `TemplateLoader` to use for loading included |
384 templates | |
385 :param encoding: the encoding of the `source` | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
386 :param lookup: the variable lookup mechanism; either "strict" (the |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
387 default), "lenient", or a custom lookup class |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
388 :param allow_exec: whether Python code blocks in templates should be |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
389 allowed |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
390 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
391 :note: Changed in 0.5: Added the `allow_exec` argument |
500 | 392 """ |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
393 self.filepath = filepath or filename |
500 | 394 self.filename = filename |
395 self.loader = loader | |
396 self.lookup = lookup | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
397 self.allow_exec = allow_exec |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
398 self._init_filters() |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
399 self._init_loader() |
828
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
400 self._module = None |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
401 self._prepared = False |
500 | 402 |
403 if isinstance(source, basestring): | |
404 source = StringIO(source) | |
405 else: | |
406 source = source | |
407 try: | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
408 self._stream = self._parse(source, encoding) |
500 | 409 except ParseError, e: |
410 raise TemplateSyntaxError(e.msg, self.filepath, e.lineno, e.offset) | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
411 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
412 def __getstate__(self): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
413 state = self.__dict__.copy() |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
414 state['filters'] = [] |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
415 return state |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
416 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
417 def __setstate__(self, state): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
418 self.__dict__ = state |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
419 self._init_filters() |
500 | 420 |
421 def __repr__(self): | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
422 return '<%s "%s">' % (type(self).__name__, self.filename) |
500 | 423 |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
424 def _init_filters(self): |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
425 self.filters = [self._flatten, self._include] |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
426 |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
427 def _init_loader(self): |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
428 if self.loader is None: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
429 from genshi.template.loader import TemplateLoader |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
430 if self.filename: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
431 if self.filepath != self.filename: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
432 basedir = os.path.normpath(self.filepath)[:-len( |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
433 os.path.normpath(self.filename)) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
434 ] |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
435 else: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
436 basedir = os.path.dirname(self.filename) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
437 else: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
438 basedir = '.' |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
439 self.loader = TemplateLoader([os.path.abspath(basedir)]) |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
440 |
830 | 441 @property |
442 def stream(self): | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
443 if not self._prepared: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
444 self._stream = list(self._prepare(self._stream)) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
445 self._prepared = True |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
446 return self._stream |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
447 |
500 | 448 def _parse(self, source, encoding): |
449 """Parse the template. | |
450 | |
451 The parsing stage parses the template and constructs a list of | |
452 directives that will be executed in the render stage. The input is | |
453 split up into literal output (text that does not depend on the context | |
454 data) and directives or expressions. | |
455 | |
456 :param source: a file-like object containing the XML source of the | |
457 template, or an XML event stream | |
458 :param encoding: the encoding of the `source` | |
459 """ | |
460 raise NotImplementedError | |
461 | |
462 def _prepare(self, stream): | |
463 """Call the `attach` method of every directive found in the template. | |
464 | |
465 :param stream: the event stream of the template | |
466 """ | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
467 from genshi.template.loader import TemplateNotFound |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
468 |
500 | 469 for kind, data, pos in stream: |
470 if kind is SUB: | |
471 directives = [] | |
472 substream = data[1] | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
473 for _, cls, value, namespaces, pos in sorted(data[0]): |
500 | 474 directive, substream = cls.attach(self, substream, value, |
475 namespaces, pos) | |
476 if directive: | |
477 directives.append(directive) | |
478 substream = self._prepare(substream) | |
479 if directives: | |
480 yield kind, (directives, list(substream)), pos | |
481 else: | |
482 for event in substream: | |
483 yield event | |
484 else: | |
485 if kind is INCLUDE: | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
486 href, cls, fallback = data |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
487 if isinstance(href, basestring) and \ |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
488 not getattr(self.loader, 'auto_reload', True): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
489 # If the path to the included template is static, and |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
490 # auto-reloading is disabled on the template loader, |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
491 # the template is inlined into the stream |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
492 try: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
493 tmpl = self.loader.load(href, relative_to=pos[0], |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
494 cls=cls or self.__class__) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
495 for event in tmpl.stream: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
496 yield event |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
497 except TemplateNotFound: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
498 if fallback is None: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
499 raise |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
500 for event in self._prepare(fallback): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
501 yield event |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
502 continue |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
503 elif fallback: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
504 # Otherwise the include is performed at run time |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
505 data = href, cls, list(self._prepare(fallback)) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
506 |
500 | 507 yield kind, data, pos |
508 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
509 def compile(self): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
510 """Compile the template to a Python module, and return the module |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
511 object. |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
512 """ |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
513 from imp import new_module |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
514 from genshi.template.inline import inline |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
515 |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
516 name = (self.filename or '_some_ident').replace('.', '_') |
828
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
517 module = ModuleType(name) |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
518 source = u'\n'.join(list(inline(self))) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
519 code = compile(source, self.filepath or '<string>', 'exec') |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
520 exec code in module.__dict__, module.__dict__ |
828
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
521 self._module = module |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
522 return self |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
523 |
500 | 524 def generate(self, *args, **kwargs): |
525 """Apply the template to the given context data. | |
526 | |
527 Any keyword arguments are made available to the template as context | |
528 data. | |
529 | |
530 Only one positional argument is accepted: if it is provided, it must be | |
531 an instance of the `Context` class, and keyword arguments are ignored. | |
532 This calling style is used for internal processing. | |
533 | |
534 :return: a markup event stream representing the result of applying | |
535 the template to the context data. | |
536 """ | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
537 vars = {} |
500 | 538 if args: |
539 assert len(args) == 1 | |
540 ctxt = args[0] | |
541 if ctxt is None: | |
542 ctxt = Context(**kwargs) | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
543 else: |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
544 vars = kwargs |
500 | 545 assert isinstance(ctxt, Context) |
546 else: | |
547 ctxt = Context(**kwargs) | |
548 | |
828
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
549 if self._module is not None: |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
550 stream = self._module.generate(ctxt) |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
551 for filter_ in [f for f in self.filters if f != self._flatten]: |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
552 stream = filter_(iter(stream), ctxt, **vars) |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
553 else: |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
554 stream = self.stream |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
555 for filter_ in self.filters: |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
556 stream = filter_(iter(stream), ctxt, **vars) |
eb8aa8690480
inline branch: template object can be compiled, and remembers the generated module.
cmlenz
parents:
820
diff
changeset
|
557 |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
558 return Stream(stream, self.serializer) |
500 | 559 |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
560 def _flatten(self, stream, ctxt, **vars): |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
561 number_conv = self._number_conv |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
562 stack = [] |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
563 push = stack.append |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
564 pop = stack.pop |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
565 stream = iter(stream) |
500 | 566 |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
567 while 1: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
568 for kind, data, pos in stream: |
500 | 569 |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
570 if kind is START and data[1]: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
571 # Attributes may still contain expressions in start tags at |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
572 # this point, so do some evaluation |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
573 tag, attrs = data |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
574 new_attrs = [] |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
575 for name, value in attrs: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
576 if type(value) is list: # this is an interpolated string |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
577 values = [event[1] |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
578 for event in self._flatten(value, ctxt, **vars) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
579 if event[0] is TEXT and event[1] is not None |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
580 ] |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
581 if not values: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
582 continue |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
583 value = ''.join(values) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
584 new_attrs.append((name, value)) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
585 yield kind, (tag, Attrs(new_attrs)), pos |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
586 |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
587 elif kind is EXPR: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
588 result = _eval_expr(data, ctxt, vars) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
589 if result is not None: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
590 # First check for a string, otherwise the iterable test |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
591 # below succeeds, and the string will be chopped up into |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
592 # individual characters |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
593 if isinstance(result, basestring): |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
594 yield TEXT, result, pos |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
595 elif isinstance(result, (int, float, long)): |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
596 yield TEXT, number_conv(result), pos |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
597 elif hasattr(result, '__iter__'): |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
598 push(stream) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
599 stream = _ensure(result) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
600 break |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
601 else: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
602 yield TEXT, unicode(result), pos |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
603 |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
604 elif kind is SUB: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
605 # This event is a list of directives and a list of nested |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
606 # events to which those directives should be applied |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
607 push(stream) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
608 stream = _apply_directives(data[1], data[0], ctxt, vars) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
609 break |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
610 |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
611 elif kind is EXEC: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
612 _exec_suite(data, ctxt, vars) |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
613 |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
614 else: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
615 yield kind, data, pos |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
616 |
500 | 617 else: |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
618 if not stack: |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
619 break |
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
620 stream = pop() |
500 | 621 |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
622 def _include(self, stream, ctxt, **vars): |
500 | 623 """Internal stream filter that performs inclusion of external |
624 template files. | |
625 """ | |
626 from genshi.template.loader import TemplateNotFound | |
627 | |
628 for event in stream: | |
629 if event[0] is INCLUDE: | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
630 href, cls, fallback = event[1] |
500 | 631 if not isinstance(href, basestring): |
632 parts = [] | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
633 for subkind, subdata, subpos in self._flatten(href, ctxt, |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
634 **vars): |
500 | 635 if subkind is TEXT: |
636 parts.append(subdata) | |
902
09cc3627654c
Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents:
830
diff
changeset
|
637 href = ''.join([x for x in parts if x is not None]) |
500 | 638 try: |
639 tmpl = self.loader.load(href, relative_to=event[2][0], | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
640 cls=cls or self.__class__) |
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
641 for event in tmpl.generate(ctxt, **vars): |
500 | 642 yield event |
643 except TemplateNotFound: | |
644 if fallback is None: | |
645 raise | |
646 for filter_ in self.filters: | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
647 fallback = filter_(iter(fallback), ctxt, **vars) |
500 | 648 for event in fallback: |
649 yield event | |
650 else: | |
651 yield event | |
652 | |
653 | |
820
1837f39efd6f
Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents:
500
diff
changeset
|
654 EXEC = Template.EXEC |
500 | 655 EXPR = Template.EXPR |
656 INCLUDE = Template.INCLUDE | |
657 SUB = Template.SUB |