1 # -*- coding: utf-8 -*-
6 Provides a class that holds runtime and parsing time options.
8 :copyright: 2007 by Armin Ronacher.
9 :license: BSD, see LICENSE for more details.
12 from jinja2.lexer import Lexer
13 from jinja2.parser import Parser
14 from jinja2.optimizer import optimize
15 from jinja2.compiler import generate
16 from jinja2.runtime import Undefined
17 from jinja2.debug import translate_exception
18 from jinja2.defaults import DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE
21 class Environment(object):
22 """The Jinja environment.
24 The core component of Jinja is the `Environment`. It contains
25 important shared variables like configuration, filters, tests,
29 #: if this environment is sandboxed. Modifying this variable won't make
30 #: the environment sandboxed though. For a real sandboxed environment
31 #: have a look at jinja2.sandbox
35 block_start_string='{%',
36 block_end_string='%}',
37 variable_start_string='{{',
38 variable_end_string='}}',
39 comment_start_string='{#',
40 comment_end_string='#}',
41 line_statement_prefix=None,
47 """Here the possible initialization parameters:
49 ========================= ============================================
50 `block_start_string` the string marking the begin of a block.
51 this defaults to ``'{%'``.
52 `block_end_string` the string marking the end of a block.
54 `variable_start_string` the string marking the begin of a print
55 statement. defaults to ``'{{'``.
56 `comment_start_string` the string marking the begin of a
57 comment. defaults to ``'{#'``.
58 `comment_end_string` the string marking the end of a comment.
60 `line_statement_prefix` If given and a string, this will be used as
61 prefix for line based statements. See the
62 documentation for more details.
63 `trim_blocks` If this is set to ``True`` the first newline
64 after a block is removed (block, not
65 variable tag!). Defaults to ``False``.
66 `optimized` should the optimizer be enabled? Default is
68 `undefined` a subclass of `Undefined` that is used to
69 represent undefined variables.
70 `loader` the loader which should be used.
71 ========================= ============================================
75 assert issubclass(undefined, Undefined), 'undefined must be ' \
76 'a subclass of undefined because filters depend on it.'
77 assert block_start_string != variable_start_string != \
78 comment_start_string, 'block, variable and comment ' \
79 'start strings must be different'
81 # lexer / parser information
82 self.block_start_string = block_start_string
83 self.block_end_string = block_end_string
84 self.variable_start_string = variable_start_string
85 self.variable_end_string = variable_end_string
86 self.comment_start_string = comment_start_string
87 self.comment_end_string = comment_end_string
88 self.line_statement_prefix = line_statement_prefix
89 self.trim_blocks = trim_blocks
90 self.undefined = undefined
91 self.optimized = optimized
92 self.finalize = finalize
95 self.filters = DEFAULT_FILTERS.copy()
96 self.tests = DEFAULT_TESTS.copy()
97 self.globals = DEFAULT_NAMESPACE.copy()
99 # set the loader provided
103 self.lexer = Lexer(self)
105 def subscribe(self, obj, argument):
106 """Get an item or attribute of an object."""
108 return getattr(obj, str(argument))
109 except (AttributeError, UnicodeError):
112 except (TypeError, LookupError):
113 return self.undefined(obj, argument)
115 def parse(self, source, name=None):
116 """Parse the sourcecode and return the abstract syntax tree. This tree
117 of nodes is used by the compiler to convert the template into
118 executable source- or bytecode.
120 parser = Parser(self, source, name)
121 return parser.parse()
123 def lex(self, source, name=None):
124 """Lex the given sourcecode and return a generator that yields tokens.
125 The stream returned is not usable for Jinja but can be used if
126 Jinja templates should be processed by other tools (for example
127 syntax highlighting etc)
129 The tuples are returned in the form ``(lineno, token, value)``.
131 return self.lexer.tokeniter(source, name)
133 def compile(self, source, name=None, filename=None, raw=False,
135 """Compile a node or source."""
136 if isinstance(source, basestring):
137 source = self.parse(source, name)
139 node = optimize(source, self, globals or {})
140 source = generate(node, self, name, filename)
144 filename = '<from_string>'
145 elif isinstance(filename, unicode):
146 filename = filename.encode('utf-8')
147 return compile(source, filename, 'exec')
149 def join_path(self, template, parent):
150 """Join a template with the parent. By default all the lookups are
151 relative to the loader root, but if the paths should be relative this
152 function can be used to calculate the real filename."""
155 def get_template(self, name, parent=None, globals=None):
156 """Load a template."""
157 if self.loader is None:
158 raise TypeError('no loader for this environment specified')
159 if parent is not None:
160 name = self.join_path(name, parent)
161 globals = self.make_globals(globals)
162 return self.loader.load(self, name, globals)
164 def from_string(self, source, globals=None):
165 """Load a template from a string."""
166 globals = self.make_globals(globals)
167 return Template(self, self.compile(source, globals=globals),
170 def make_globals(self, d):
171 """Return a dict for the globals."""
174 return dict(self.globals, **d)
177 class Template(object):
178 """Represents a template."""
180 def __init__(self, environment, code, globals):
181 namespace = {'environment': environment}
182 exec code in namespace
183 self.environment = environment
184 self.name = namespace['name']
185 self.filename = code.co_filename
186 self.root_render_func = namespace['root']
187 self.blocks = namespace['blocks']
188 self.globals = globals
191 self._get_debug_info = namespace['get_debug_info']
192 namespace['__jinja_template__'] = self
194 def render(self, *args, **kwargs):
195 return u''.join(self.generate(*args, **kwargs))
197 def stream(self, *args, **kwargs):
198 return TemplateStream(self.generate(*args, **kwargs))
200 def generate(self, *args, **kwargs):
201 # assemble the context
202 context = dict(*args, **kwargs)
204 # if the environment is using the optimizer locals may never
205 # override globals as optimizations might have happened
206 # depending on values of certain globals. This assertion goes
207 # away if the python interpreter is started with -O
208 if __debug__ and self.environment.optimized:
209 overrides = set(context) & set(self.globals)
211 plural = len(overrides) != 1 and 's' or ''
212 raise AssertionError('the per template variable%s %s '
213 'override%s global variable%s. '
214 'With an enabled optimizer this '
215 'will lead to unexpected results.' %
216 (plural, ', '.join(overrides), plural or ' a', plural))
217 gen = self.root_render_func(dict(self.globals, **context))
218 # skip the first item which is a reference to the context
225 exc_info = translate_exception(sys.exc_info())
226 raise exc_info[0], exc_info[1], exc_info[2]
228 def get_corresponding_lineno(self, lineno):
229 """Return the source line number of a line number in the
230 generated bytecode as they are not in sync.
232 for template_line, code_line in reversed(self._get_debug_info()):
233 if code_line <= lineno:
239 self.__class__.__name__,
244 class TemplateStream(object):
245 """Wraps a genererator for outputing template streams."""
247 def __init__(self, gen):
249 self._next = gen.next
250 self.buffered = False
252 def disable_buffering(self):
253 """Disable the output buffering."""
254 self._next = self._gen.next
255 self.buffered = False
257 def enable_buffering(self, size=5):
258 """Enable buffering. Buffer `size` items before yielding them."""
260 raise ValueError('buffer size too small')
263 def buffering_next():
267 next = self._gen.next
276 raise StopIteration()
277 except StopIteration:
282 self._next = buffering_next