annotate genshi/template/base.py @ 639:8e11a6693bb3 trunk

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!
author cmlenz
date Mon, 17 Sep 2007 23:11:21 +0000
parents 699601cce3cc
children 25d0368491ac 3d7288f373bd 08f22328303d
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
14 """Basic templating functionality."""
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
44
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
45 :param message: the error message
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
46 :param filename: the filename of the template
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
47 :param lineno: the number of line in the template at which the error
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
48 occurred
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
49 :param offset: the column number at which the error occurred
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
68 """Create the exception
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
69
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
70 :param message: the error message
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
71 :param filename: the filename of the template
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
72 :param lineno: the number of line in the template at which the error
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
73 occurred
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
74 :param offset: the column number at which the error occurred
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
90 """Create the exception
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
91
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
92 :param name: the name of the directive
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
93 :param filename: the filename of the template
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
94 :param lineno: the number of line in the template at which the error
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
95 occurred
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
133 """Initialize the template context with the given keyword arguments as
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
134 data.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
139 self._match_templates = []
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
158 """Return whether a variable exists in any of the scopes.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
159
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
160 :param key: the name of the variable
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
166 """Remove a variable from all scopes.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
167
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
168 :param key: the name of the variable
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
178 :param key: the name of the variable
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
179 :return: the variable value
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
91556138dae5 Add support for `len()` to the `Context` class.
cmlenz
parents: 407
diff changeset
187 def __len__(self):
435
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
188 """Return the number of distinctly named variables in the context.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
189
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
190 :return: the number of variables in the context
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
191 """
420
91556138dae5 Add support for `len()` to the `Context` class.
cmlenz
parents: 407
diff changeset
192 return len(self.items())
91556138dae5 Add support for `len()` to the `Context` class.
cmlenz
parents: 407
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
195 """Set a variable in the current scope.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
196
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
197 :param key: the name of the variable
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
198 :param value: the variable value
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
205 Intended primarily for internal use by directives.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
206
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
207 :param key: the name of the variable
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
208 :param default: the default value to return when the variable is not
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
219
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
220 :param key: the name of the variable
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
221 :param default: the default value to return when the variable is not
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
230 """Return the name of all variables in the context.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
231
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
232 :return: a list of variable names
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
240 """Return a list of ``(name, value)`` tuples for all variables in the
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
241 context.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
242
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
243 :return: a list of variables
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
248 """Push a new scope on the stack.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
249
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
250 :param data: the data dictionary to push on the context stack.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
257 def _apply_directives(stream, ctxt, directives):
435
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
258 """Apply the given directives to the stream.
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
259
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
260 :param stream: the stream the directives should be applied to
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
261 :param ctxt: the `Context`
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
262 :param directives: the list of directives to apply
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
263 :return: the stream with the given directives applied
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
264 """
336
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
265 if directives:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
266 stream = directives[0](iter(stream), ctxt, directives[1:])
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
267 return stream
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
268
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
269
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
270 class TemplateMeta(type):
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
271 """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
272
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
273 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
274 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
275 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
276 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
277
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
278 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
279
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
280
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
281 class Template(object):
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
282 """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
283
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
284 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
285 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
286 """
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
287 __metaclass__ = TemplateMeta
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
288
609
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
289 EXEC = StreamEventKind('EXEC')
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
290 """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
291
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
292 EXPR = StreamEventKind('EXPR')
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
293 """Stream event kind representing a Python expression."""
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
294
475
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
295 INCLUDE = StreamEventKind('INCLUDE')
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
296 """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
297
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
298 SUB = StreamEventKind('SUB')
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
299 """Stream event kind representing a nested stream to which one or more
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
300 directives should be applied.
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
301 """
336
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
302
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
303 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
304 _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
305
336
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
306 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
307 encoding=None, lookup='strict', allow_exec=True):
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
308 """Initialize a template from either a string, a file-like object, or
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
309 an already parsed markup stream.
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
310
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
311 :param source: a string, file-like object, or markup stream to read the
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
312 template from
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
313 :param basedir: the base directory containing the template file; when
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
314 loaded from a `TemplateLoader`, this will be the
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
315 directory on the template search path in which the
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
316 template was found
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
317 :param filename: the name of the template file, relative to the given
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
318 base directory
492
fd10321bb1ba Fix docstring typo.
cmlenz
parents: 475
diff changeset
319 :param loader: the `TemplateLoader` to use for loading included
fd10321bb1ba Fix docstring typo.
cmlenz
parents: 475
diff changeset
320 templates
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
321 :param encoding: the encoding of the `source`
606
37ff75bb4301 Changed the default error handling mode to "strict".
cmlenz
parents: 605
diff changeset
322 :param lookup: the variable lookup mechanism; either "strict" (the
37ff75bb4301 Changed the default error handling mode to "strict".
cmlenz
parents: 605
diff changeset
323 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
324 :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
325 allowed
619340e2d805 Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents: 492
diff changeset
326
619340e2d805 Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents: 492
diff changeset
327 :note: Changed in 0.5: Added the `allow_exec` argument
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
328 """
336
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
329 self.basedir = basedir
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
330 self.filename = filename
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
331 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
332 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
333 else:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
334 self.filepath = filename
363
37e4b4bb0b53 Parse template includes at parse time to avoid some runtime overhead.
cmlenz
parents: 362
diff changeset
335 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
336 self.lookup = lookup
545
619340e2d805 Support for Python code blocks in templates can now be disabled. Closes #123.
cmlenz
parents: 492
diff changeset
337 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
338
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
339 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
340 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
341 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
342
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
343 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
344 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
345 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
346 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
347 try:
5692bc32ba5f * Better method to propogate the full path to the template file on parse errors. Supersedes r513.
cmlenz
parents: 427
diff changeset
348 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
349 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
350 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
351
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
352 def __repr__(self):
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
353 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
354
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
355 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
356 """Parse the template.
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
357
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
358 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
359 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
360 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
361 data) and directives or expressions.
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
362
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
363 :param source: a file-like object containing the XML source of the
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
364 template, or an XML event stream
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
365 :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
366 """
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
367 raise NotImplementedError
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
368
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
369 def _prepare(self, stream):
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
370 """Call the `attach` method of every directive found in the template.
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
371
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
372 :param stream: the event stream of the template
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
373 """
548
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
374 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
375
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
376 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
377 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
378 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
379 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
380 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
381 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
382 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
383 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
384 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
385 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
386 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
387 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
388 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
389 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
390 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
391 else:
475
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
392 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
393 href, cls, fallback = data
548
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
394 if isinstance(href, basestring) and \
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
395 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
396 # 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
397 # 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
398 # 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
399 try:
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
400 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
401 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
402 for event in tmpl.stream:
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
403 yield event
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
404 except TemplateNotFound:
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
405 if fallback is None:
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
406 raise
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
407 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
408 yield event
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
409 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
410 elif fallback:
548
1cc1afc39176 Implement static includes, which improves performance a bit when auto reloading is disabled.
cmlenz
parents: 545
diff changeset
411 # 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
412 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
413
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
414 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
415
336
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
416 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
417 """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
418
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
419 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
420 data.
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
421
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
422 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
423 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
424 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
425
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
426 :return: a markup event stream representing the result of applying
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
427 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
428 """
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
429 if args:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
430 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
431 ctxt = args[0]
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
432 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
433 ctxt = Context(**kwargs)
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
434 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
435 else:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
436 ctxt = Context(**kwargs)
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
437
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
438 stream = self.stream
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
439 for filter_ in self.filters:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
440 stream = filter_(iter(stream), ctxt)
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
441 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
442
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
443 def _eval(self, stream, ctxt):
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
444 """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
445 `TEXT` events.
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
446 """
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
447 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
448 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
449
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
450 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
451
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
452 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
453 # 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
454 # this point, so do some evaluation
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
455 tag, attrs = data
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
456 new_attrs = []
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
457 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
458 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
459 value = substream
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
460 else:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
461 values = []
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
462 for subkind, subdata, subpos in self._eval(substream,
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
463 ctxt):
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
464 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
465 values.append(subdata)
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
466 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
467 if not value:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
468 continue
345
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
469 new_attrs.append((name, u''.join(value)))
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
470 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
471
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
472 elif kind is EXPR:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
473 result = data.evaluate(ctxt)
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
474 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
475 # 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
476 # 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
477 # individual characters
336
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
478 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
479 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
480 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
481 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
482 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
483 substream = _ensure(result)
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
484 for filter_ in filters:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
485 substream = filter_(substream, ctxt)
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
486 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
487 yield event
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
488 else:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
489 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
490
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
491 else:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
492 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
493
609
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
494 def _exec(self, stream, ctxt):
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
495 """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
496 for event in stream:
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
497 if event[0] is EXEC:
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
498 event[1].execute(_ctxt2dict(ctxt))
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
499 else:
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
500 yield event
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
501
336
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
502 def _flatten(self, stream, ctxt):
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
503 """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
504 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
505 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
506 # 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
507 # 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
508 directives, substream = event[1]
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
509 substream = _apply_directives(substream, ctxt, directives)
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
510 for event in self._flatten(substream, ctxt):
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
511 yield event
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
512 else:
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
513 yield event
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
514
475
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
515 def _include(self, stream, ctxt):
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
516 """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
517 template files.
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
518 """
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
519 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
520
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
521 for event in stream:
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
522 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
523 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
524 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
525 parts = []
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
526 for subkind, subdata, subpos in self._eval(href, ctxt):
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
527 if subkind is TEXT:
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
528 parts.append(subdata)
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
529 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
530 try:
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
531 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
532 cls=cls or self.__class__)
475
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
533 for event in tmpl.generate(ctxt):
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
534 yield event
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
535 except TemplateNotFound:
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
536 if fallback is None:
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
537 raise
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
538 for filter_ in self.filters:
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
539 fallback = filter_(iter(fallback), ctxt)
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
540 for event in fallback:
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
541 yield event
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
542 else:
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
543 yield event
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
544
336
7763f7aec949 Refactoring: `genshi.template` is now a package, it was getting way to crowded in that file.
cmlenz
parents:
diff changeset
545
609
6d4877844e28 Add support for Python code blocks in text templates using the new syntax.
cmlenz
parents: 606
diff changeset
546 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
547 EXPR = Template.EXPR
475
b373f80f7763 Added include directive for text templates (#115). Thanks to Alastair for the original patch.
cmlenz
parents: 442
diff changeset
548 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
549 SUB = Template.SUB
Copyright (C) 2012-2017 Edgewall Software