Mercurial > genshi > mirror
annotate genshi/template/base.py @ 1012:cdb5d435d237 trunk
Fix assert with side-effect in xi:fallback directive processing (see #565).
author | hodgestar |
---|---|
date | Mon, 17 Jun 2013 20:52:21 +0000 |
parents | 0f9fe59dfa00 |
children | 6fc92535c888 5dccab13ec85 |
rev | line source |
---|---|
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
1 # -*- coding: utf-8 -*- |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
2 # |
897 | 3 # Copyright (C) 2006-2010 Edgewall Software |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
4 # All rights reserved. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
5 # |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
6 # This software is licensed as described in the file COPYING, which |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
7 # you should have received as part of this distribution. The terms |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
8 # are also available at http://genshi.edgewall.org/wiki/License. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
9 # |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
10 # This software consists of voluntary contributions made by many |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
11 # individuals. For the exact contribution history, see the revision |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
12 # history and logs, available at http://genshi.edgewall.org/log/. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
13 |
427 | 14 """Basic templating functionality.""" |
15 | |
822
70fddd2262f5
Get rid of some Python 2.3 legacy that's no longer needed now that 2.4 is the baseline.
cmlenz
parents:
817
diff
changeset
|
16 from collections import deque |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
17 import os |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
18 import sys |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
19 |
935 | 20 from genshi.compat import StringIO, BytesIO |
636
699601cce3cc
Follow-up to [751]: applying the optimization to text templates was actually slowing them down, so only do it for markup templates.
cmlenz
parents:
635
diff
changeset
|
21 from genshi.core import Attrs, Stream, StreamEventKind, START, TEXT, _ensure |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
22 from genshi.input import ParseError |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
23 |
790
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
24 __all__ = ['Context', 'DirectiveFactory', 'Template', 'TemplateError', |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
25 'TemplateRuntimeError', 'TemplateSyntaxError', 'BadDirectiveError'] |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
420
diff
changeset
|
26 __docformat__ = 'restructuredtext en' |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
27 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
28 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
29 class TemplateError(Exception): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
30 """Base exception class for errors related to template processing.""" |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
31 |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
32 def __init__(self, message, filename=None, lineno=-1, offset=-1): |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
33 """Create the exception. |
435 | 34 |
35 :param message: the error message | |
36 :param filename: the filename of the template | |
37 :param lineno: the number of line in the template at which the error | |
38 occurred | |
39 :param offset: the column number at which the error occurred | |
40 """ | |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
41 if filename is None: |
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
42 filename = '<string>' |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
43 self.msg = message #: the error message string |
407
f37d8e6acdf2
Move string interpolation code into separate module (`genshi.template.interpolation`).
cmlenz
parents:
405
diff
changeset
|
44 if filename != '<string>' or lineno >= 0: |
f37d8e6acdf2
Move string interpolation code into separate module (`genshi.template.interpolation`).
cmlenz
parents:
405
diff
changeset
|
45 message = '%s (%s, line %d)' % (self.msg, filename, lineno) |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
46 Exception.__init__(self, message) |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
47 self.filename = filename #: the name of the template file |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
48 self.lineno = lineno #: the number of the line containing the error |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
49 self.offset = offset #: the offset on the line |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
50 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
51 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
52 class TemplateSyntaxError(TemplateError): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
53 """Exception raised when an expression in a template causes a Python syntax |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
54 error, or the template is not well-formed. |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
55 """ |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
56 |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
57 def __init__(self, message, filename=None, lineno=-1, offset=-1): |
435 | 58 """Create the exception |
59 | |
60 :param message: the error message | |
61 :param filename: the filename of the template | |
62 :param lineno: the number of line in the template at which the error | |
63 occurred | |
64 :param offset: the column number at which the error occurred | |
65 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
66 if isinstance(message, SyntaxError) and message.lineno is not None: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
67 message = str(message).replace(' (line %d)' % message.lineno, '') |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
68 TemplateError.__init__(self, message, filename, lineno) |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
69 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
70 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
71 class BadDirectiveError(TemplateSyntaxError): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
72 """Exception raised when an unknown directive is encountered when parsing |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
73 a template. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
74 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
75 An unknown directive is any attribute using the namespace for directives, |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
76 with a local name that doesn't match any registered directive. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
77 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
78 |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
79 def __init__(self, name, filename=None, lineno=-1): |
435 | 80 """Create the exception |
81 | |
82 :param name: the name of the directive | |
83 :param filename: the filename of the template | |
84 :param lineno: the number of line in the template at which the error | |
85 occurred | |
86 """ | |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
87 TemplateSyntaxError.__init__(self, 'bad directive "%s"' % name, |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
88 filename, lineno) |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
89 |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
90 |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
91 class TemplateRuntimeError(TemplateError): |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
92 """Exception raised when an the evaluation of a Python expression in a |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
93 template causes an error. |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
94 """ |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
95 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
96 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
97 class Context(object): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
98 """Container for template input data. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
99 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
100 A context provides a stack of scopes (represented by dictionaries). |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
101 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
102 Template directives such as loops can push a new scope on the stack with |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
103 data that should only be available inside the loop. When the loop |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
104 terminates, that scope can get popped off the stack again. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
105 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
106 >>> ctxt = Context(one='foo', other=1) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
107 >>> ctxt.get('one') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
108 'foo' |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
109 >>> ctxt.get('other') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
110 1 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
111 >>> ctxt.push(dict(one='frost')) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
112 >>> ctxt.get('one') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
113 'frost' |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
114 >>> ctxt.get('other') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
115 1 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
116 >>> ctxt.pop() |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
117 {'one': 'frost'} |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
118 >>> ctxt.get('one') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
119 'foo' |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
120 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
121 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
122 def __init__(self, **data): |
435 | 123 """Initialize the template context with the given keyword arguments as |
124 data. | |
125 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
126 self.frames = deque([data]) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
127 self.pop = self.frames.popleft |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
128 self.push = self.frames.appendleft |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
129 self._match_templates = [] |
553
489a47873950
Store state information for py:choose outside of the regular context data.
cmlenz
parents:
548
diff
changeset
|
130 self._choice_stack = [] |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
131 |
442
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
132 # Helper functions for use in expressions |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
133 def defined(name): |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
134 """Return whether a variable with the specified name exists in the |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
135 expression scope.""" |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
136 return name in self |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
137 def value_of(name, default=None): |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
138 """If a variable of the specified name is defined, return its value. |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
139 Otherwise, return the provided default value, or ``None``.""" |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
140 return self.get(name, default) |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
141 data.setdefault('defined', defined) |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
142 data.setdefault('value_of', value_of) |
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
143 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
144 def __repr__(self): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
145 return repr(list(self.frames)) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
146 |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
147 def __contains__(self, key): |
435 | 148 """Return whether a variable exists in any of the scopes. |
149 | |
150 :param key: the name of the variable | |
151 """ | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
152 return self._find(key)[1] is not None |
564
aeb89e9730df
Alias `__contains__` to `has_key` in `Context` class for code outside of Genshi that may expect that for some wild reason.
cmlenz
parents:
553
diff
changeset
|
153 has_key = __contains__ |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
154 |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
155 def __delitem__(self, key): |
435 | 156 """Remove a variable from all scopes. |
157 | |
158 :param key: the name of the variable | |
159 """ | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
160 for frame in self.frames: |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
161 if key in frame: |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
162 del frame[key] |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
163 |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
164 def __getitem__(self, key): |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
165 """Get a variables's value, starting at the current scope and going |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
166 upward. |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
167 |
435 | 168 :param key: the name of the variable |
169 :return: the variable value | |
170 :raises KeyError: if the requested variable wasn't found in any scope | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
171 """ |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
172 value, frame = self._find(key) |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
173 if frame is None: |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
174 raise KeyError(key) |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
175 return value |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
176 |
420 | 177 def __len__(self): |
435 | 178 """Return the number of distinctly named variables in the context. |
179 | |
180 :return: the number of variables in the context | |
181 """ | |
420 | 182 return len(self.items()) |
183 | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
184 def __setitem__(self, key, value): |
435 | 185 """Set a variable in the current scope. |
186 | |
187 :param key: the name of the variable | |
188 :param value: the variable value | |
189 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
190 self.frames[0][key] = value |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
191 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
192 def _find(self, key, default=None): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
193 """Retrieve a given variable's value and the frame it was found in. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
194 |
435 | 195 Intended primarily for internal use by directives. |
196 | |
197 :param key: the name of the variable | |
198 :param default: the default value to return when the variable is not | |
199 found | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
200 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
201 for frame in self.frames: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
202 if key in frame: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
203 return frame[key], frame |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
204 return default, None |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
205 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
206 def get(self, key, default=None): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
207 """Get a variable's value, starting at the current scope and going |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
208 upward. |
435 | 209 |
210 :param key: the name of the variable | |
211 :param default: the default value to return when the variable is not | |
212 found | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
213 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
214 for frame in self.frames: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
215 if key in frame: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
216 return frame[key] |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
217 return default |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
218 |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
219 def keys(self): |
435 | 220 """Return the name of all variables in the context. |
221 | |
222 :return: a list of variable names | |
223 """ | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
224 keys = [] |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
225 for frame in self.frames: |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
226 keys += [key for key in frame if key not in keys] |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
227 return keys |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
228 |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
229 def items(self): |
435 | 230 """Return a list of ``(name, value)`` tuples for all variables in the |
231 context. | |
232 | |
233 :return: a list of variables | |
234 """ | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
235 return [(key, self.get(key)) for key in self.keys()] |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
236 |
731
01bdf155db95
Workaround for a Python 2.4 bug that broke star imports in template code blocks. Closes #221. Many thanks to Armin Ronacher for the patch.
cmlenz
parents:
715
diff
changeset
|
237 def update(self, mapping): |
01bdf155db95
Workaround for a Python 2.4 bug that broke star imports in template code blocks. Closes #221. Many thanks to Armin Ronacher for the patch.
cmlenz
parents:
715
diff
changeset
|
238 """Update the context from the mapping provided.""" |
01bdf155db95
Workaround for a Python 2.4 bug that broke star imports in template code blocks. Closes #221. Many thanks to Armin Ronacher for the patch.
cmlenz
parents:
715
diff
changeset
|
239 self.frames[0].update(mapping) |
01bdf155db95
Workaround for a Python 2.4 bug that broke star imports in template code blocks. Closes #221. Many thanks to Armin Ronacher for the patch.
cmlenz
parents:
715
diff
changeset
|
240 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
241 def push(self, data): |
435 | 242 """Push a new scope on the stack. |
243 | |
244 :param data: the data dictionary to push on the context stack. | |
245 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
246 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
247 def pop(self): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
248 """Pop the top-most scope from the stack.""" |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
249 |
947
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
250 def copy(self): |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
251 """Create a copy of this Context object.""" |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
252 # required to make f_locals a dict-like object |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
253 # See http://genshi.edgewall.org/ticket/249 for |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
254 # example use case in Twisted tracebacks |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
255 ctxt = Context() |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
256 ctxt.frames.pop() # pop empty dummy context |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
257 ctxt.frames.extend(self.frames) |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
258 ctxt._match_templates.extend(self._match_templates) |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
259 ctxt._choice_stack.extend(self._choice_stack) |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
260 return ctxt |
0f9fe59dfa00
Add .copy() function to Context objects. Fixes #249.
hodgestar
parents:
935
diff
changeset
|
261 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
262 |
827
bebc68529176
Avoid varargs on internal functions in template processing for slightly better performance.
cmlenz
parents:
825
diff
changeset
|
263 def _apply_directives(stream, directives, ctxt, vars): |
435 | 264 """Apply the given directives to the stream. |
265 | |
266 :param stream: the stream the directives should be applied to | |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
267 :param directives: the list of directives to apply |
435 | 268 :param ctxt: the `Context` |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
269 :param vars: additional variables that should be available when Python |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
270 code is executed |
435 | 271 :return: the stream with the given directives applied |
272 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
273 if directives: |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
274 stream = directives[0](iter(stream), directives[1:], ctxt, **vars) |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
275 return stream |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
276 |
827
bebc68529176
Avoid varargs on internal functions in template processing for slightly better performance.
cmlenz
parents:
825
diff
changeset
|
277 |
bebc68529176
Avoid varargs on internal functions in template processing for slightly better performance.
cmlenz
parents:
825
diff
changeset
|
278 def _eval_expr(expr, ctxt, vars=None): |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
279 """Evaluate the given `Expression` object. |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
280 |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
281 :param expr: the expression to evaluate |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
282 :param ctxt: the `Context` |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
283 :param vars: additional variables that should be available to the |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
284 expression |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
285 :return: the result of the evaluation |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
286 """ |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
287 if vars: |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
288 ctxt.push(vars) |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
289 retval = expr.evaluate(ctxt) |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
290 if vars: |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
291 ctxt.pop() |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
292 return retval |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
293 |
827
bebc68529176
Avoid varargs on internal functions in template processing for slightly better performance.
cmlenz
parents:
825
diff
changeset
|
294 |
bebc68529176
Avoid varargs on internal functions in template processing for slightly better performance.
cmlenz
parents:
825
diff
changeset
|
295 def _exec_suite(suite, ctxt, vars=None): |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
296 """Execute the given `Suite` object. |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
297 |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
298 :param suite: the code suite to execute |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
299 :param ctxt: the `Context` |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
300 :param vars: additional variables that should be available to the |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
301 code |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
302 """ |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
303 if vars: |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
304 ctxt.push(vars) |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
305 ctxt.push({}) |
750 | 306 suite.execute(ctxt) |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
307 if vars: |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
308 top = ctxt.pop() |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
309 ctxt.pop() |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
310 ctxt.frames[0].update(top) |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
311 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
312 |
790
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
313 class DirectiveFactoryMeta(type): |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
314 """Meta class for directive factories.""" |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
315 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
316 def __new__(cls, name, bases, d): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
317 if 'directives' in d: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
318 d['_dir_by_name'] = dict(d['directives']) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
319 d['_dir_order'] = [directive[1] for directive in d['directives']] |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
320 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
321 return type.__new__(cls, name, bases, d) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
322 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
323 |
790
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
324 class DirectiveFactory(object): |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
325 """Base for classes that provide a set of template directives. |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
326 |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
327 :since: version 0.6 |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
328 """ |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
329 __metaclass__ = DirectiveFactoryMeta |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
330 |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
331 directives = [] |
848 | 332 """A list of ``(name, cls)`` tuples that define the set of directives |
790
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
333 provided by this factory. |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
334 """ |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
335 |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
336 def get_directive(self, name): |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
337 """Return the directive class for the given name. |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
338 |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
339 :param name: the directive name as used in the template |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
340 :return: the directive class |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
341 :see: `Directive` |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
342 """ |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
343 return self._dir_by_name.get(name) |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
344 |
847
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
345 def get_directive_index(self, dir_cls): |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
346 """Return a key for the given directive class that should be used to |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
347 sort it among other directives on the same `SUB` event. |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
348 |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
349 The default implementation simply returns the index of the directive in |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
350 the `directives` list. |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
351 |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
352 :param dir_cls: the directive class |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
353 :return: the sort key |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
354 """ |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
355 if dir_cls in self._dir_order: |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
356 return self._dir_order.index(dir_cls) |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
357 return len(self._dir_order) |
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
358 |
790
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
359 |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
360 class Template(DirectiveFactory): |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
361 """Abstract template base class. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
362 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
363 This class implements most of the template processing model, but does not |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
364 specify the syntax of templates. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
365 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
366 |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
367 EXEC = StreamEventKind('EXEC') |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
368 """Stream event kind representing a Python code suite to execute.""" |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
369 |
427 | 370 EXPR = StreamEventKind('EXPR') |
371 """Stream event kind representing a Python expression.""" | |
372 | |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
373 INCLUDE = StreamEventKind('INCLUDE') |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
374 """Stream event kind representing the inclusion of another template.""" |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
375 |
427 | 376 SUB = StreamEventKind('SUB') |
377 """Stream event kind representing a nested stream to which one or more | |
378 directives should be applied. | |
379 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
380 |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
590
diff
changeset
|
381 serializer = None |
636
699601cce3cc
Follow-up to [751]: applying the optimization to text templates was actually slowing them down, so only do it for markup templates.
cmlenz
parents:
635
diff
changeset
|
382 _number_conv = unicode # function used to convert numbers to event data |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
590
diff
changeset
|
383 |
714
fc6d9d2a3527
The `Template` class and its subclasses, as well as the interpolation API, now take an `filepath` parameter instead of `basedir`. Closes #207. Thanks to Waldemar Kornewald for the patch.
cmlenz
parents:
700
diff
changeset
|
384 def __init__(self, source, filepath=None, filename=None, loader=None, |
606
37ff75bb4301
Changed the default error handling mode to "strict".
cmlenz
parents:
605
diff
changeset
|
385 encoding=None, lookup='strict', allow_exec=True): |
427 | 386 """Initialize a template from either a string, a file-like object, or |
387 an already parsed markup stream. | |
388 | |
389 :param source: a string, file-like object, or markup stream to read the | |
390 template from | |
714
fc6d9d2a3527
The `Template` class and its subclasses, as well as the interpolation API, now take an `filepath` parameter instead of `basedir`. Closes #207. Thanks to Waldemar Kornewald for the patch.
cmlenz
parents:
700
diff
changeset
|
391 :param filepath: the absolute path to the template file |
fc6d9d2a3527
The `Template` class and its subclasses, as well as the interpolation API, now take an `filepath` parameter instead of `basedir`. Closes #207. Thanks to Waldemar Kornewald for the patch.
cmlenz
parents:
700
diff
changeset
|
392 :param filename: the path to the template file relative to the search |
fc6d9d2a3527
The `Template` class and its subclasses, as well as the interpolation API, now take an `filepath` parameter instead of `basedir`. Closes #207. Thanks to Waldemar Kornewald for the patch.
cmlenz
parents:
700
diff
changeset
|
393 path |
492 | 394 :param loader: the `TemplateLoader` to use for loading included |
395 templates | |
427 | 396 :param encoding: the encoding of the `source` |
606
37ff75bb4301
Changed the default error handling mode to "strict".
cmlenz
parents:
605
diff
changeset
|
397 :param lookup: the variable lookup mechanism; either "strict" (the |
37ff75bb4301
Changed the default error handling mode to "strict".
cmlenz
parents:
605
diff
changeset
|
398 default), "lenient", or a custom lookup class |
545
619340e2d805
Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents:
492
diff
changeset
|
399 :param allow_exec: whether Python code blocks in templates should be |
619340e2d805
Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents:
492
diff
changeset
|
400 allowed |
619340e2d805
Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents:
492
diff
changeset
|
401 |
619340e2d805
Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents:
492
diff
changeset
|
402 :note: Changed in 0.5: Added the `allow_exec` argument |
427 | 403 """ |
714
fc6d9d2a3527
The `Template` class and its subclasses, as well as the interpolation API, now take an `filepath` parameter instead of `basedir`. Closes #207. Thanks to Waldemar Kornewald for the patch.
cmlenz
parents:
700
diff
changeset
|
404 self.filepath = filepath or filename |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
405 self.filename = filename |
363
37e4b4bb0b53
Parse template includes at parse time to avoid some runtime overhead.
cmlenz
parents:
362
diff
changeset
|
406 self.loader = loader |
442
97544725bb7f
Back out [510] and instead implement configurable error handling modes. The default is the old 0.3.x behaviour, but more strict error handling is available as an option.
cmlenz
parents:
438
diff
changeset
|
407 self.lookup = lookup |
545
619340e2d805
Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents:
492
diff
changeset
|
408 self.allow_exec = allow_exec |
715 | 409 self._init_filters() |
876
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
410 self._init_loader() |
790
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
411 self._prepared = False |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
412 |
935 | 413 if not isinstance(source, Stream) and not hasattr(source, 'read'): |
414 if isinstance(source, unicode): | |
415 source = StringIO(source) | |
416 else: | |
417 source = BytesIO(source) | |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
418 try: |
790
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
419 self._stream = self._parse(source, encoding) |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
420 except ParseError, e: |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
421 raise TemplateSyntaxError(e.msg, self.filepath, e.lineno, e.offset) |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
422 |
715 | 423 def __getstate__(self): |
424 state = self.__dict__.copy() | |
425 state['filters'] = [] | |
426 return state | |
427 | |
428 def __setstate__(self, state): | |
429 self.__dict__ = state | |
430 self._init_filters() | |
431 | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
432 def __repr__(self): |
860
16d55698006a
A bit of cleanup of the `Markup` Python implementation.
cmlenz
parents:
855
diff
changeset
|
433 return '<%s "%s">' % (type(self).__name__, self.filename) |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
434 |
715 | 435 def _init_filters(self): |
876
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
436 self.filters = [self._flatten, self._include] |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
437 |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
438 def _init_loader(self): |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
439 if self.loader is None: |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
440 from genshi.template.loader import TemplateLoader |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
441 if self.filename: |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
442 if self.filepath != self.filename: |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
443 basedir = os.path.normpath(self.filepath)[:-len( |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
444 os.path.normpath(self.filename)) |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
445 ] |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
446 else: |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
447 basedir = os.path.dirname(self.filename) |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
448 else: |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
449 basedir = '.' |
124b57282f81
Templates instantiated without a loader now get an implicit loader based on their file path, or the current directory as a fallback. Closes #320.
cmlenz
parents:
860
diff
changeset
|
450 self.loader = TemplateLoader([os.path.abspath(basedir)]) |
715 | 451 |
822
70fddd2262f5
Get rid of some Python 2.3 legacy that's no longer needed now that 2.4 is the baseline.
cmlenz
parents:
817
diff
changeset
|
452 @property |
70fddd2262f5
Get rid of some Python 2.3 legacy that's no longer needed now that 2.4 is the baseline.
cmlenz
parents:
817
diff
changeset
|
453 def stream(self): |
790
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
454 if not self._prepared: |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
455 self._stream = list(self._prepare(self._stream)) |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
456 self._prepared = True |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
457 return self._stream |
da90cee22560
Merged the custom-directives branch back into trunk.
cmlenz
parents:
750
diff
changeset
|
458 |
374
b146277eb54a
`MarkupTemplate`s can now be instantiated from markup streams, in addition to strings and file-like objects. Thanks to David Fraser for the patch. Closes #69.
cmlenz
parents:
363
diff
changeset
|
459 def _parse(self, source, encoding): |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
460 """Parse the template. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
461 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
462 The parsing stage parses the template and constructs a list of |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
463 directives that will be executed in the render stage. The input is |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
464 split up into literal output (text that does not depend on the context |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
465 data) and directives or expressions. |
427 | 466 |
467 :param source: a file-like object containing the XML source of the | |
468 template, or an XML event stream | |
469 :param encoding: the encoding of the `source` | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
470 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
471 raise NotImplementedError |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
472 |
351
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
473 def _prepare(self, stream): |
427 | 474 """Call the `attach` method of every directive found in the template. |
475 | |
476 :param stream: the event stream of the template | |
477 """ | |
548
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
478 from genshi.template.loader import TemplateNotFound |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
479 |
351
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
480 for kind, data, pos in stream: |
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
481 if kind is SUB: |
362
fe40d34fb71d
Follow-up to [431]: directives are no longer instantiated directly at parse time, but instead by the `attach()` method of the directive class (which replaces the `prepare()` method).
cmlenz
parents:
361
diff
changeset
|
482 directives = [] |
fe40d34fb71d
Follow-up to [431]: directives are no longer instantiated directly at parse time, but instead by the `attach()` method of the directive class (which replaces the `prepare()` method).
cmlenz
parents:
361
diff
changeset
|
483 substream = data[1] |
847
e16447a9605f
Backported a couple of templating core changes from the advanced-i18n branch, in particular considering the determination of directive ordering../set
cmlenz
parents:
843
diff
changeset
|
484 for _, cls, value, namespaces, pos in sorted(data[0]): |
362
fe40d34fb71d
Follow-up to [431]: directives are no longer instantiated directly at parse time, but instead by the `attach()` method of the directive class (which replaces the `prepare()` method).
cmlenz
parents:
361
diff
changeset
|
485 directive, substream = cls.attach(self, substream, value, |
fe40d34fb71d
Follow-up to [431]: directives are no longer instantiated directly at parse time, but instead by the `attach()` method of the directive class (which replaces the `prepare()` method).
cmlenz
parents:
361
diff
changeset
|
486 namespaces, pos) |
fe40d34fb71d
Follow-up to [431]: directives are no longer instantiated directly at parse time, but instead by the `attach()` method of the directive class (which replaces the `prepare()` method).
cmlenz
parents:
361
diff
changeset
|
487 if directive: |
fe40d34fb71d
Follow-up to [431]: directives are no longer instantiated directly at parse time, but instead by the `attach()` method of the directive class (which replaces the `prepare()` method).
cmlenz
parents:
361
diff
changeset
|
488 directives.append(directive) |
351
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
489 substream = self._prepare(substream) |
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
490 if directives: |
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
491 yield kind, (directives, list(substream)), pos |
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
492 else: |
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
493 for event in substream: |
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
494 yield event |
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
495 else: |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
496 if kind is INCLUDE: |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
497 href, cls, fallback = data |
548
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
498 if isinstance(href, basestring) and \ |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
499 not getattr(self.loader, 'auto_reload', True): |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
500 # If the path to the included template is static, and |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
501 # auto-reloading is disabled on the template loader, |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
502 # the template is inlined into the stream |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
503 try: |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
504 tmpl = self.loader.load(href, relative_to=pos[0], |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
505 cls=cls or self.__class__) |
548
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
506 for event in tmpl.stream: |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
507 yield event |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
508 except TemplateNotFound: |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
509 if fallback is None: |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
510 raise |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
511 for event in self._prepare(fallback): |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
512 yield event |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
513 continue |
590
36b5a03534a0
Fix includes so that they again raise an exception when the included template is not found and no fallback has been provided.
cmlenz
parents:
564
diff
changeset
|
514 elif fallback: |
548
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
515 # Otherwise the include is performed at run time |
639
8e11a6693bb3
Fix for XInclude fallbacks when auto-reloading is enabled. Closes #147. Thanks to rintaro@cpan.org for reporting the issue and providing a patch and test case!
cmlenz
parents:
636
diff
changeset
|
516 data = href, cls, list(self._prepare(fallback)) |
548
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
517 |
351
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
518 yield kind, data, pos |
0cc031745884
The `py:content`, `py:replace`, and `py:strip=""` directives are now expanded when the template is loaded (as opposed to when it's rendered).
cmlenz
parents:
345
diff
changeset
|
519 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
520 def generate(self, *args, **kwargs): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
521 """Apply the template to the given context data. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
522 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
523 Any keyword arguments are made available to the template as context |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
524 data. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
525 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
526 Only one positional argument is accepted: if it is provided, it must be |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
527 an instance of the `Context` class, and keyword arguments are ignored. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
528 This calling style is used for internal processing. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
529 |
427 | 530 :return: a markup event stream representing the result of applying |
531 the template to the context data. | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
532 """ |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
533 vars = {} |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
534 if args: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
535 assert len(args) == 1 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
536 ctxt = args[0] |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
537 if ctxt is None: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
538 ctxt = Context(**kwargs) |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
539 else: |
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
540 vars = kwargs |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
541 assert isinstance(ctxt, Context) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
542 else: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
543 ctxt = Context(**kwargs) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
544 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
545 stream = self.stream |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
546 for filter_ in self.filters: |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
547 stream = filter_(iter(stream), ctxt, **vars) |
605
d0345c64da65
Text templates now default to rendering as plain text; it is no longer necessary to explicitly specify the "text" method to the `render()` or `serialize()` method of the generated markup stream. See tickets #62 and #118.
cmlenz
parents:
590
diff
changeset
|
548 return Stream(stream, self.serializer) |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
549 |
813
ae8727f7e1e1
Merge the internal template filters `_eval` and `_exec` into the `_flatten` function for slightly better performance.
cmlenz
parents:
790
diff
changeset
|
550 def _flatten(self, stream, ctxt, **vars): |
636
699601cce3cc
Follow-up to [751]: applying the optimization to text templates was actually slowing them down, so only do it for markup templates.
cmlenz
parents:
635
diff
changeset
|
551 number_conv = self._number_conv |
843
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
552 stack = [] |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
553 push = stack.append |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
554 pop = stack.pop |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
555 stream = iter(stream) |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
556 |
843
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
557 while 1: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
558 for kind, data, pos in stream: |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
559 |
843
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
560 if kind is START and data[1]: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
561 # Attributes may still contain expressions in start tags at |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
562 # this point, so do some evaluation |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
563 tag, attrs = data |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
564 new_attrs = [] |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
565 for name, value in attrs: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
566 if type(value) is list: # this is an interpolated string |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
567 values = [event[1] |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
568 for event in self._flatten(value, ctxt, **vars) |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
569 if event[0] is TEXT and event[1] is not None |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
570 ] |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
571 if not values: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
572 continue |
855 | 573 value = ''.join(values) |
843
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
574 new_attrs.append((name, value)) |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
575 yield kind, (tag, Attrs(new_attrs)), pos |
813
ae8727f7e1e1
Merge the internal template filters `_eval` and `_exec` into the `_flatten` function for slightly better performance.
cmlenz
parents:
790
diff
changeset
|
576 |
843
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
577 elif kind is EXPR: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
578 result = _eval_expr(data, ctxt, vars) |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
579 if result is not None: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
580 # First check for a string, otherwise the iterable test |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
581 # below succeeds, and the string will be chopped up into |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
582 # individual characters |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
583 if isinstance(result, basestring): |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
584 yield TEXT, result, pos |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
585 elif isinstance(result, (int, float, long)): |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
586 yield TEXT, number_conv(result), pos |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
587 elif hasattr(result, '__iter__'): |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
588 push(stream) |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
589 stream = _ensure(result) |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
590 break |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
591 else: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
592 yield TEXT, unicode(result), pos |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
593 |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
594 elif kind is SUB: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
595 # This event is a list of directives and a list of nested |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
596 # events to which those directives should be applied |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
597 push(stream) |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
598 stream = _apply_directives(data[1], data[0], ctxt, vars) |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
599 break |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
600 |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
601 elif kind is EXEC: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
602 _exec_suite(data, ctxt, vars) |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
603 |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
604 else: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
605 yield kind, data, pos |
813
ae8727f7e1e1
Merge the internal template filters `_eval` and `_exec` into the `_flatten` function for slightly better performance.
cmlenz
parents:
790
diff
changeset
|
606 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
607 else: |
843
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
608 if not stack: |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
609 break |
d10e5bceaa1f
Refactored the template flattening method to be less recursive.
cmlenz
parents:
827
diff
changeset
|
610 stream = pop() |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
611 |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
612 def _include(self, stream, ctxt, **vars): |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
613 """Internal stream filter that performs inclusion of external |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
614 template files. |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
615 """ |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
616 from genshi.template.loader import TemplateNotFound |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
617 |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
618 for event in stream: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
619 if event[0] is INCLUDE: |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
620 href, cls, fallback = event[1] |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
621 if not isinstance(href, basestring): |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
622 parts = [] |
813
ae8727f7e1e1
Merge the internal template filters `_eval` and `_exec` into the `_flatten` function for slightly better performance.
cmlenz
parents:
790
diff
changeset
|
623 for subkind, subdata, subpos in self._flatten(href, ctxt, |
ae8727f7e1e1
Merge the internal template filters `_eval` and `_exec` into the `_flatten` function for slightly better performance.
cmlenz
parents:
790
diff
changeset
|
624 **vars): |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
625 if subkind is TEXT: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
626 parts.append(subdata) |
855 | 627 href = ''.join([x for x in parts if x is not None]) |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
628 try: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
629 tmpl = self.loader.load(href, relative_to=event[2][0], |
610
5e358de79e4c
* XInclude elements in markup templates now support the `parse` attribute; when set to "xml" (the default), the include is processed as before, but when set to "text", the included template is parsed as a text template using the new syntax (ticket #101).
cmlenz
parents:
609
diff
changeset
|
630 cls=cls or self.__class__) |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
631 for event in tmpl.generate(ctxt, **vars): |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
632 yield event |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
633 except TemplateNotFound: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
634 if fallback is None: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
635 raise |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
636 for filter_ in self.filters: |
700
08f22328303d
Add option for unbuffered match template processing, which could cause excessive memory usage. Closes #190.
cmlenz
parents:
639
diff
changeset
|
637 fallback = filter_(iter(fallback), ctxt, **vars) |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
638 for event in fallback: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
639 yield event |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
640 else: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
641 yield event |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
642 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
643 |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
644 EXEC = Template.EXEC |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
645 EXPR = Template.EXPR |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
646 INCLUDE = Template.INCLUDE |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
647 SUB = Template.SUB |