Mercurial > genshi > mirror
annotate genshi/template/base.py @ 703:af57b12e3dd2 experimental-match-fastpaths
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
author | aflett |
---|---|
date | Mon, 31 Mar 2008 22:47:50 +0000 |
parents | 3d7288f373bd |
children | 422d0607ba85 |
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 # |
407
f37d8e6acdf2
Move string interpolation code into separate module (`genshi.template.interpolation`).
cmlenz
parents:
405
diff
changeset
|
3 # Copyright (C) 2006-2007 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 | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
16 try: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
17 from collections import deque |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
18 except ImportError: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
19 class deque(list): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
20 def appendleft(self, x): self.insert(0, x) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
21 def popleft(self): return self.pop(0) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
22 import os |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
23 from StringIO import StringIO |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
24 import sys |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
25 |
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
|
26 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
|
27 from genshi.input import ParseError |
687
3d7288f373bd
land first cut at fast-path matching - needs some cleanup
aflett
parents:
639
diff
changeset
|
28 from genshi.template.match import MatchSet |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
29 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
30 __all__ = ['Context', 'Template', 'TemplateError', 'TemplateRuntimeError', |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
31 'TemplateSyntaxError', 'BadDirectiveError'] |
425
073640758a42
Try to use proper reStructuredText for docstrings throughout.
cmlenz
parents:
420
diff
changeset
|
32 __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
|
33 |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
34 if sys.version_info < (2, 4): |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
35 _ctxt2dict = lambda ctxt: ctxt.frames[0] |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
36 else: |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
37 _ctxt2dict = lambda ctxt: ctxt |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
38 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
39 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
40 class TemplateError(Exception): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
41 """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
|
42 |
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
|
43 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
|
44 """Create the exception. |
435 | 45 |
46 :param message: the error message | |
47 :param filename: the filename of the template | |
48 :param lineno: the number of line in the template at which the error | |
49 occurred | |
50 :param offset: the column number at which the error occurred | |
51 """ | |
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
|
52 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
|
53 filename = '<string>' |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
54 self.msg = message #: the error message string |
407
f37d8e6acdf2
Move string interpolation code into separate module (`genshi.template.interpolation`).
cmlenz
parents:
405
diff
changeset
|
55 if filename != '<string>' or lineno >= 0: |
f37d8e6acdf2
Move string interpolation code into separate module (`genshi.template.interpolation`).
cmlenz
parents:
405
diff
changeset
|
56 message = '%s (%s, line %d)' % (self.msg, filename, lineno) |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
57 Exception.__init__(self, message) |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
58 self.filename = filename #: the name of the template file |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
59 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
|
60 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
|
61 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
62 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
63 class TemplateSyntaxError(TemplateError): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
64 """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
|
65 error, or the template is not well-formed. |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
66 """ |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
67 |
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
|
68 def __init__(self, message, filename=None, lineno=-1, offset=-1): |
435 | 69 """Create the exception |
70 | |
71 :param message: the error message | |
72 :param filename: the filename of the template | |
73 :param lineno: the number of line in the template at which the error | |
74 occurred | |
75 :param offset: the column number at which the error occurred | |
76 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
77 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
|
78 message = str(message).replace(' (line %d)' % message.lineno, '') |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
79 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
|
80 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
81 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
82 class BadDirectiveError(TemplateSyntaxError): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
83 """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
|
84 a template. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
85 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
86 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
|
87 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
|
88 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
89 |
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
|
90 def __init__(self, name, filename=None, lineno=-1): |
435 | 91 """Create the exception |
92 | |
93 :param name: the name of the directive | |
94 :param filename: the filename of the template | |
95 :param lineno: the number of line in the template at which the error | |
96 occurred | |
97 """ | |
438
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
98 TemplateSyntaxError.__init__(self, 'bad directive "%s"' % name, |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
99 filename, lineno) |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
100 |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
101 |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
102 class TemplateRuntimeError(TemplateError): |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
103 """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
|
104 template causes an error. |
2c38ec4e2dff
Added documentation page on the builtin stream filters.
cmlenz
parents:
435
diff
changeset
|
105 """ |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
106 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
107 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
108 class Context(object): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
109 """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
|
110 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
111 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
|
112 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
113 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
|
114 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
|
115 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
|
116 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
117 >>> 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
|
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 >>> ctxt.get('other') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
121 1 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
122 >>> 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
|
123 >>> ctxt.get('one') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
124 'frost' |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
125 >>> ctxt.get('other') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
126 1 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
127 >>> ctxt.pop() |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
128 {'one': 'frost'} |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
129 >>> ctxt.get('one') |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
130 'foo' |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
131 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
132 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
133 def __init__(self, **data): |
435 | 134 """Initialize the template context with the given keyword arguments as |
135 data. | |
136 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
137 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
|
138 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
|
139 self.push = self.frames.appendleft |
687
3d7288f373bd
land first cut at fast-path matching - needs some cleanup
aflett
parents:
639
diff
changeset
|
140 self._match_set = MatchSet() |
553
489a47873950
Store state information for py:choose outside of the regular context data.
cmlenz
parents:
548
diff
changeset
|
141 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
|
142 |
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
|
143 # 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
|
144 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
|
145 """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
|
146 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
|
147 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
|
148 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
|
149 """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
|
150 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
|
151 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
|
152 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
|
153 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
|
154 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
155 def __repr__(self): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
156 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
|
157 |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
158 def __contains__(self, key): |
435 | 159 """Return whether a variable exists in any of the scopes. |
160 | |
161 :param key: the name of the variable | |
162 """ | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
163 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
|
164 has_key = __contains__ |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
165 |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
166 def __delitem__(self, key): |
435 | 167 """Remove a variable from all scopes. |
168 | |
169 :param key: the name of the variable | |
170 """ | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
171 for frame in self.frames: |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
172 if key in frame: |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
173 del frame[key] |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
174 |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
175 def __getitem__(self, key): |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
176 """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
|
177 upward. |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
178 |
435 | 179 :param key: the name of the variable |
180 :return: the variable value | |
181 :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
|
182 """ |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
183 value, frame = self._find(key) |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
184 if frame is None: |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
185 raise KeyError(key) |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
186 return value |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
187 |
420 | 188 def __len__(self): |
435 | 189 """Return the number of distinctly named variables in the context. |
190 | |
191 :return: the number of variables in the context | |
192 """ | |
420 | 193 return len(self.items()) |
194 | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
195 def __setitem__(self, key, value): |
435 | 196 """Set a variable in the current scope. |
197 | |
198 :param key: the name of the variable | |
199 :param value: the variable value | |
200 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
201 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
|
202 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
203 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
|
204 """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
|
205 |
435 | 206 Intended primarily for internal use by directives. |
207 | |
208 :param key: the name of the variable | |
209 :param default: the default value to return when the variable is not | |
210 found | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
211 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
212 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
|
213 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
|
214 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
|
215 return default, None |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
216 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
217 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
|
218 """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
|
219 upward. |
435 | 220 |
221 :param key: the name of the variable | |
222 :param default: the default value to return when the variable is not | |
223 found | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
224 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
225 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
|
226 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
|
227 return frame[key] |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
228 return default |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
229 |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
230 def keys(self): |
435 | 231 """Return the name of all variables in the context. |
232 | |
233 :return: a list of variable names | |
234 """ | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
235 keys = [] |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
236 for frame in self.frames: |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
237 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
|
238 return keys |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
239 |
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
240 def items(self): |
435 | 241 """Return a list of ``(name, value)`` tuples for all variables in the |
242 context. | |
243 | |
244 :return: a list of variables | |
245 """ | |
405
5340931530e2
Support for Python code blocks using the `<?python ?>` processing instruction. Closes #84.
cmlenz
parents:
400
diff
changeset
|
246 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
|
247 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
248 def push(self, data): |
435 | 249 """Push a new scope on the stack. |
250 | |
251 :param data: the data dictionary to push on the context stack. | |
252 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
253 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
254 def pop(self): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
255 """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
|
256 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
257 |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
258 def _apply_directives(stream, directives, ctxt, **vars): |
435 | 259 """Apply the given directives to the stream. |
260 | |
261 :param stream: the stream the directives should be applied to | |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
262 :param directives: the list of directives to apply |
435 | 263 :param ctxt: the `Context` |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
264 :param vars: additional variables that should be available when Python |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
265 code is executed |
435 | 266 :return: the stream with the given directives applied |
267 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
268 if directives: |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
269 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
|
270 return stream |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
271 |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
272 def _eval_expr(expr, ctxt, **vars): |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
273 """Evaluate the given `Expression` object. |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
274 |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
275 :param expr: the expression to evaluate |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
276 :param ctxt: the `Context` |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
277 :param vars: additional variables that should be available to the |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
278 expression |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
279 :return: the result of the evaluation |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
280 """ |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
281 if vars: |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
282 ctxt.push(vars) |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
283 retval = expr.evaluate(ctxt) |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
284 if vars: |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
285 ctxt.pop() |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
286 return retval |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
287 |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
288 def _exec_suite(suite, ctxt, **vars): |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
289 """Execute the given `Suite` object. |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
290 |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
291 :param suite: the code suite to execute |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
292 :param ctxt: the `Context` |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
293 :param vars: additional variables that should be available to the |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
294 code |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
295 """ |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
296 if vars: |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
297 ctxt.push(vars) |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
298 ctxt.push({}) |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
299 suite.execute(_ctxt2dict(ctxt)) |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
300 if vars: |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
301 top = ctxt.pop() |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
302 ctxt.pop() |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
303 ctxt.frames[0].update(top) |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
304 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
305 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
306 class TemplateMeta(type): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
307 """Meta class for templates.""" |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
308 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
309 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
|
310 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
|
311 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
|
312 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
|
313 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
314 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
|
315 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
316 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
317 class Template(object): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
318 """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
|
319 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
320 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
|
321 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
|
322 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
323 __metaclass__ = TemplateMeta |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
324 |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
325 EXEC = StreamEventKind('EXEC') |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
326 """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
|
327 |
427 | 328 EXPR = StreamEventKind('EXPR') |
329 """Stream event kind representing a Python expression.""" | |
330 | |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
331 INCLUDE = StreamEventKind('INCLUDE') |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
332 """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
|
333 |
427 | 334 SUB = StreamEventKind('SUB') |
335 """Stream event kind representing a nested stream to which one or more | |
336 directives should be applied. | |
337 """ | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
338 |
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
|
339 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
|
340 _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
|
341 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
342 def __init__(self, source, basedir=None, filename=None, loader=None, |
606
37ff75bb4301
Changed the default error handling mode to "strict".
cmlenz
parents:
605
diff
changeset
|
343 encoding=None, lookup='strict', allow_exec=True): |
427 | 344 """Initialize a template from either a string, a file-like object, or |
345 an already parsed markup stream. | |
346 | |
347 :param source: a string, file-like object, or markup stream to read the | |
348 template from | |
349 :param basedir: the base directory containing the template file; when | |
350 loaded from a `TemplateLoader`, this will be the | |
351 directory on the template search path in which the | |
352 template was found | |
353 :param filename: the name of the template file, relative to the given | |
354 base directory | |
492 | 355 :param loader: the `TemplateLoader` to use for loading included |
356 templates | |
427 | 357 :param encoding: the encoding of the `source` |
606
37ff75bb4301
Changed the default error handling mode to "strict".
cmlenz
parents:
605
diff
changeset
|
358 :param lookup: the variable lookup mechanism; either "strict" (the |
37ff75bb4301
Changed the default error handling mode to "strict".
cmlenz
parents:
605
diff
changeset
|
359 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
|
360 :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
|
361 allowed |
619340e2d805
Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents:
492
diff
changeset
|
362 |
619340e2d805
Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents:
492
diff
changeset
|
363 :note: Changed in 0.5: Added the `allow_exec` argument |
427 | 364 """ |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
365 self.basedir = basedir |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
366 self.filename = filename |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
367 if basedir and filename: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
368 self.filepath = os.path.join(basedir, filename) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
369 else: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
370 self.filepath = filename |
363
37e4b4bb0b53
Parse template includes at parse time to avoid some runtime overhead.
cmlenz
parents:
362
diff
changeset
|
371 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
|
372 self.lookup = lookup |
545
619340e2d805
Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents:
492
diff
changeset
|
373 self.allow_exec = allow_exec |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
374 |
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
|
375 self.filters = [self._flatten, self._eval, self._exec] |
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
|
376 if loader: |
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
|
377 self.filters.append(self._include) |
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
|
378 |
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
|
379 if isinstance(source, basestring): |
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
|
380 source = StringIO(source) |
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
|
381 else: |
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
|
382 source = source |
434
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
383 try: |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
384 self.stream = list(self._prepare(self._parse(source, encoding))) |
5692bc32ba5f
* Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents:
427
diff
changeset
|
385 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
|
386 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
|
387 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
388 def __repr__(self): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
389 return '<%s "%s">' % (self.__class__.__name__, self.filename) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
390 |
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
|
391 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
|
392 """Parse the template. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
393 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
394 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
|
395 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
|
396 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
|
397 data) and directives or expressions. |
427 | 398 |
399 :param source: a file-like object containing the XML source of the | |
400 template, or an XML event stream | |
401 :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
|
402 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
403 raise NotImplementedError |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
404 |
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
|
405 def _prepare(self, stream): |
427 | 406 """Call the `attach` method of every directive found in the template. |
407 | |
408 :param stream: the event stream of the template | |
409 """ | |
548
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
410 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
|
411 |
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
|
412 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
|
413 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
|
414 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
|
415 substream = data[1] |
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
|
416 for cls, value, namespaces, pos in data[0]: |
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
|
417 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
|
418 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
|
419 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
|
420 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
|
421 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
|
422 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
|
423 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
|
424 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
|
425 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
|
426 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
|
427 else: |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
428 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
|
429 href, cls, fallback = data |
548
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
430 if isinstance(href, basestring) and \ |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
431 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
|
432 # 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
|
433 # 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
|
434 # 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
|
435 try: |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
436 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
|
437 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
|
438 for event in tmpl.stream: |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
439 yield event |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
440 except TemplateNotFound: |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
441 if fallback is None: |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
442 raise |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
443 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
|
444 yield event |
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
445 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
|
446 elif fallback: |
548
1cc1afc39176
Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents:
545
diff
changeset
|
447 # 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
|
448 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
|
449 |
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
|
450 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
|
451 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
452 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
|
453 """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
|
454 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
455 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
|
456 data. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
457 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
458 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
|
459 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
|
460 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
|
461 |
427 | 462 :return: a markup event stream representing the result of applying |
463 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
|
464 """ |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
465 vars = {} |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
466 if args: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
467 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
|
468 ctxt = args[0] |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
469 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
|
470 ctxt = Context(**kwargs) |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
471 else: |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
472 vars = kwargs |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
473 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
|
474 else: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
475 ctxt = Context(**kwargs) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
476 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
477 stream = self.stream |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
478 for filter_ in self.filters: |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
479 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
|
480 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
|
481 |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
482 def _eval(self, stream, ctxt, **vars): |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
483 """Internal stream filter that evaluates any expressions in `START` and |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
484 `TEXT` events. |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
485 """ |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
486 filters = (self._flatten, self._eval) |
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
|
487 number_conv = self._number_conv |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
488 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
489 for kind, data, pos in stream: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
490 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
491 if kind is START and data[1]: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
492 # Attributes may still contain expressions in start tags at |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
493 # this point, so do some evaluation |
345 | 494 tag, attrs = data |
495 new_attrs = [] | |
496 for name, substream in attrs: | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
497 if isinstance(substream, basestring): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
498 value = substream |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
499 else: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
500 values = [] |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
501 for subkind, subdata, subpos in self._eval(substream, |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
502 ctxt, |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
503 **vars): |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
504 if subkind is TEXT: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
505 values.append(subdata) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
506 value = [x for x in values if x is not None] |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
507 if not value: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
508 continue |
345 | 509 new_attrs.append((name, u''.join(value))) |
510 yield kind, (tag, Attrs(new_attrs)), pos | |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
511 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
512 elif kind is EXPR: |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
513 result = _eval_expr(data, ctxt, **vars) |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
514 if result is not None: |
635
7e666e3e4f1b
Minor performance improvement for expressions that evaluate to numbers: the result is wrapped in a `Markup` object, meaning we'll not have to escape the string in the serialization stage.
cmlenz
parents:
610
diff
changeset
|
515 # First check for a string, otherwise the iterable test |
7e666e3e4f1b
Minor performance improvement for expressions that evaluate to numbers: the result is wrapped in a `Markup` object, meaning we'll not have to escape the string in the serialization stage.
cmlenz
parents:
610
diff
changeset
|
516 # below succeeds, and the string will be chopped up into |
7e666e3e4f1b
Minor performance improvement for expressions that evaluate to numbers: the result is wrapped in a `Markup` object, meaning we'll not have to escape the string in the serialization stage.
cmlenz
parents:
610
diff
changeset
|
517 # individual characters |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
518 if isinstance(result, basestring): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
519 yield TEXT, result, pos |
635
7e666e3e4f1b
Minor performance improvement for expressions that evaluate to numbers: the result is wrapped in a `Markup` object, meaning we'll not have to escape the string in the serialization stage.
cmlenz
parents:
610
diff
changeset
|
520 elif isinstance(result, (int, float, long)): |
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
|
521 yield TEXT, number_conv(result), pos |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
522 elif hasattr(result, '__iter__'): |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
523 substream = _ensure(result) |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
524 for filter_ in filters: |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
525 substream = filter_(substream, ctxt, **vars) |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
526 for event in substream: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
527 yield event |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
528 else: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
529 yield TEXT, unicode(result), pos |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
530 |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
531 else: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
532 yield kind, data, pos |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
533 |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
534 def _exec(self, stream, ctxt, **vars): |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
535 """Internal stream filter that executes Python code blocks.""" |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
536 for event in stream: |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
537 if event[0] is EXEC: |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
538 _exec_suite(event[1], ctxt, **vars) |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
539 else: |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
540 yield event |
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
541 |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
542 def _flatten(self, stream, ctxt, **vars): |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
543 """Internal stream filter that expands `SUB` events in the stream.""" |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
544 for event in stream: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
545 if event[0] is SUB: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
546 # This event is a list of directives and a list of nested |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
547 # events to which those directives should be applied |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
548 directives, substream = event[1] |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
549 substream = _apply_directives(substream, directives, ctxt, |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
550 **vars) |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
551 for event in self._flatten(substream, ctxt, **vars): |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
552 yield event |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
553 else: |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
554 yield event |
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
555 |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
556 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
|
557 """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
|
558 template files. |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
559 """ |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
560 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
|
561 |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
562 for event in stream: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
563 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
|
564 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
|
565 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
|
566 parts = [] |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
567 for subkind, subdata, subpos in self._eval(href, ctxt, |
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
568 **vars): |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
569 if subkind is TEXT: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
570 parts.append(subdata) |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
571 href = u''.join([x for x in parts if x is not None]) |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
572 try: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
573 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
|
574 cls=cls or self.__class__) |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
575 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
|
576 yield event |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
577 except TemplateNotFound: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
578 if fallback is None: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
579 raise |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
580 for filter_ in self.filters: |
703
af57b12e3dd2
merge in trunk up through r818 - fundamentally changed the way MatchSet works, but actually is more consistent now
aflett
parents:
687
diff
changeset
|
581 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
|
582 for event in fallback: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
583 yield event |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
584 else: |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
585 yield event |
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
586 |
336
7763f7aec949
Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff
changeset
|
587 |
609
6d4877844e28
Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents:
606
diff
changeset
|
588 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
|
589 EXPR = Template.EXPR |
475
b373f80f7763
Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents:
442
diff
changeset
|
590 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
|
591 SUB = Template.SUB |