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