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
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
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
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
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
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
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
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
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
265 :return: the stream with the given directives applied
be39660919a5 More API doc enhancements.
cmlenz
parents: 434
diff changeset
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
327 EXPR = StreamEventKind('EXPR')
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
328 """Stream event kind representing a Python expression."""
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
333 SUB = StreamEventKind('SUB')
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
334 """Stream event kind representing a nested stream to which one or more
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
335 directives should be applied.
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
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
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
343 """Initialize a template from either a string, a file-like object, or
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
344 an already parsed markup stream.
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
345
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
346 :param source: a string, file-like object, or markup stream to read the
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
347 template from
718
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
348 :param filepath: the absolute path to the template file
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
349 :param filename: the path to the template file relative to the search
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
350 path
492
fd10321bb1ba Fix docstring typo.
cmlenz
parents: 475
diff changeset
351 :param loader: the `TemplateLoader` to use for loading included
fd10321bb1ba Fix docstring typo.
cmlenz
parents: 475
diff changeset
352 templates
427
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
360 """
718
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
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
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
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
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
377 def __getstate__(self):
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
378 state = self.__dict__.copy()
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
379 state['filters'] = []
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
380 return state
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
381
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
382 def __setstate__(self, state):
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
383 self.__dict__ = state
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
384 self._init_filters()
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
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
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
389 def _init_filters(self):
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
390 self.filters = [self._flatten, self._eval, self._exec]
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
391 if self.loader:
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
392 self.filters.append(self._include)
d143dd73789b update to trunk through r833
aflett
parents: 717
diff changeset
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
401
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
402 :param source: a file-like object containing the XML source of the
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
403 template, or an XML event stream
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
409 """Call the `attach` method of every directive found in the template.
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
410
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
411 :param stream: the event stream of the template
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
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
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
465 :return: a markup event stream representing the result of applying
55c574767df2 More API documentation.
cmlenz
parents: 425
diff changeset
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
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
497 tag, attrs = data
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
498 new_attrs = []
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
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
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
512 new_attrs.append((name, u''.join(value)))
2aa7ca37ae6a Make `Attrs` instances immutable.
cmlenz
parents: 336
diff changeset
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
Copyright (C) 2012-2017 Edgewall Software