1 # -*- coding: utf-8 -*-
6 This module implements additional nodes derived from the ast base node.
8 It also provides some node tree helper functions like `in_lineno` and
9 `get_nodes` used by the parser and translator in order to normalize
10 python and jinja nodes.
12 :copyright: 2008 by Armin Ronacher.
13 :license: BSD, see LICENSE for more details.
16 from types import FunctionType
17 from itertools import chain, izip
18 from collections import deque
20 from jinja2.utils import Markup
25 '/': operator.truediv,
26 '//': operator.floordiv,
46 'in': lambda a, b: a in b,
47 'notin': lambda a, b: a not in b
51 class Impossible(Exception):
52 """Raised if the node could not perform a requested action."""
56 """A metaclass for nodes that handles the field and attribute
57 inheritance. fields and attributes from the parent class are
58 automatically forwarded to the child."""
60 def __new__(cls, name, bases, d):
61 for attr in 'fields', 'attributes':
63 storage.extend(getattr(bases[0], attr, ()))
64 storage.extend(d.get(attr, ()))
65 assert len(bases) == 1, 'multiple inheritance not allowed'
66 assert len(storage) == len(set(storage)), 'layout conflict'
67 d[attr] = tuple(storage)
68 return type.__new__(cls, name, bases, d)
72 """Baseclass for all Jinja nodes."""
73 __metaclass__ = NodeType
75 attributes = ('lineno', 'environment')
77 def __init__(self, *args, **kw):
79 if len(args) != len(self.fields):
81 raise TypeError('%r takes 0 arguments' %
82 self.__class__.__name__)
83 raise TypeError('%r takes 0 or %d argument%s' % (
84 self.__class__.__name__,
86 len(self.fields) != 1 and 's' or ''
88 for name, arg in izip(self.fields, args):
89 setattr(self, name, arg)
90 for attr in self.attributes:
91 setattr(self, attr, kw.pop(attr, None))
93 raise TypeError('unknown keyword argument %r' %
96 def iter_fields(self, exclude=()):
97 """Iterate over all fields."""
98 for name in self.fields:
99 if name not in exclude:
101 yield name, getattr(self, name)
102 except AttributeError:
105 def iter_child_nodes(self, exclude=()):
106 """Iterate over all child nodes."""
107 for field, item in self.iter_fields(exclude):
108 if isinstance(item, list):
110 if isinstance(n, Node):
112 elif isinstance(item, Node):
115 def find(self, node_type):
116 """Find the first node of a given type."""
117 for result in self.find_all(node_type):
120 def find_all(self, node_type):
121 """Find all the nodes of a given type."""
122 for child in self.iter_child_nodes():
123 if isinstance(child, node_type):
125 for result in child.find_all(node_type):
129 """Return a deep copy of the node."""
130 result = object.__new__(self.__class__)
131 for field, value in self.iter_fields():
132 if isinstance(value, Node):
133 new_value = value.copy()
134 elif isinstance(value, list):
137 if isinstance(item, Node):
141 new_value.append(item)
143 new_value = copy(value)
144 setattr(result, field, new_value)
145 for attr in self.attributes:
147 setattr(result, attr, getattr(self, attr))
148 except AttributeError:
152 def set_ctx(self, ctx):
153 """Reset the context of a node and all child nodes. Per default the
154 parser will all generate nodes that have a 'load' context as it's the
155 most common one. This method is used in the parser to set assignment
156 targets and other nodes to a store context.
160 node = todo.popleft()
161 if 'ctx' in node.fields:
163 todo.extend(node.iter_child_nodes())
165 def set_lineno(self, lineno, override=False):
166 """Set the line numbers of the node and children."""
169 node = todo.popleft()
170 if 'lineno' in node.attributes:
171 if node.lineno is None or override:
173 todo.extend(node.iter_child_nodes())
175 def set_environment(self, environment):
176 """Set the environment for all nodes."""
179 node = todo.popleft()
180 node.environment = environment
181 todo.extend(node.iter_child_nodes())
185 self.__class__.__name__,
186 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
192 """Base node for all statements."""
196 """Nodes that exist in a specific context only."""
199 class Template(Node):
200 """Node that represents a template."""
205 """A node that holds multiple expressions which are then printed out.
206 This is used both for the `print` statement and the regular template data.
210 def optimized_nodes(self):
211 """Try to optimize the nodes."""
213 for node in self.nodes:
215 const = unicode(node.as_const())
219 if buffer and isinstance(buffer[-1], unicode):
227 """Represents an extends statement."""
228 fields = ('template',)
232 """A node that represents a for loop"""
233 fields = ('target', 'iter', 'body', 'else_', 'test')
237 """A node that represents an if condition."""
238 fields = ('test', 'body', 'else_')
242 """A node that represents a macro."""
243 fields = ('name', 'args', 'defaults', 'body')
246 class CallBlock(Stmt):
247 """A node that represents am extended macro call."""
248 fields = ('call', 'args', 'defaults', 'body')
252 """Allows defining own variables."""
253 fields = ('name', 'expr')
256 class FilterBlock(Stmt):
257 """Node for filter sections."""
258 fields = ('body', 'filter')
262 """A node that represents a block."""
263 fields = ('name', 'body')
267 """A node that represents the include tag."""
268 fields = ('template', 'with_context')
272 """A node that represents the import tag."""
273 fields = ('template', 'target', 'with_context')
276 class FromImport(Stmt):
277 """A node that represents the from import tag. It's important to not
278 pass unsafe names to the name attribute. The compiler translates the
279 attribute lookups directly into getattr calls and does *not* use the
280 subscribe callback of the interface. As exported variables may not
281 start with double underscores (which the parser asserts) this is not a
282 problem for regular Jinja code, but if this node is used in an extension
283 extra care must be taken.
285 The list of names may contain tuples if aliases are wanted.
287 fields = ('template', 'names', 'with_context')
291 """A node for translatable sections."""
292 fields = ('singular', 'plural', 'indicator', 'replacements')
295 class ExprStmt(Stmt):
296 """A statement that evaluates an expression to None."""
301 """Assigns an expression to a target."""
302 fields = ('target', 'node')
306 """Baseclass for all expressions."""
309 """Return the value of the expression as constant or raise
310 `Impossible` if this was not possible.
314 def can_assign(self):
315 """Check if it's possible to assign something to this node."""
320 """Baseclass for all binary expressions."""
321 fields = ('left', 'right')
325 f = _binop_to_func[self.operator]
327 return f(self.left.as_const(), self.right.as_const())
332 class UnaryExpr(Expr):
333 """Baseclass for all unary expressions."""
338 f = _uaop_to_func[self.operator]
340 return f(self.node.as_const())
346 """any name such as {{ foo }}"""
347 fields = ('name', 'ctx')
349 def can_assign(self):
350 return self.name not in ('true', 'false', 'none')
353 class MarkSafe(Expr):
354 """Mark the wrapped expression as safe (Markup)"""
358 return Markup(self.expr.as_const())
362 """Baseclass for literals."""
365 class Const(Literal):
366 """any constat such as {{ "foo" }}"""
373 def from_untrusted(cls, value, lineno=None, environment=None):
374 """Return a const object if the value is representable as
375 constant value in the generated code, otherwise it will raise
376 an `Impossible` exception.
378 from compiler import has_safe_repr
379 if not has_safe_repr(value):
381 return cls(value, lineno=lineno, environment=environment)
384 class Tuple(Literal):
385 """For loop unpacking and some other things like multiple arguments
388 fields = ('items', 'ctx')
391 return tuple(x.as_const() for x in self.items)
393 def can_assign(self):
394 for item in self.items:
395 if not item.can_assign():
401 """any list literal such as {{ [1, 2, 3] }}"""
405 return [x.as_const() for x in self.items]
409 """any dict literal such as {{ {1: 2, 3: 4} }}"""
413 return dict(x.as_const() for x in self.items)
417 """A key, value pair for dicts."""
418 fields = ('key', 'value')
421 return self.key.as_const(), self.value.as_const()
424 class Keyword(Helper):
425 """A key, value pair for keyword arguments."""
426 fields = ('key', 'value')
429 class CondExpr(Expr):
430 """{{ foo if bar else baz }}"""
431 fields = ('test', 'expr1', 'expr2')
434 if self.test.as_const():
435 return self.expr1.as_const()
436 return self.expr2.as_const()
440 """{{ foo|bar|baz }}"""
441 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
443 def as_const(self, obj=None):
444 if self.node is obj is None:
446 filter = self.environment.filters.get(self.name)
447 if filter is None or getattr(filter, 'contextfilter', False):
450 obj = self.node.as_const()
451 args = [x.as_const() for x in self.args]
452 if getattr(filter, 'environmentfilter', False):
453 args.insert(0, self.environment)
454 kwargs = dict(x.as_const() for x in self.kwargs)
455 if self.dyn_args is not None:
457 args.extend(self.dyn_args.as_const())
460 if self.dyn_kwargs is not None:
462 kwargs.update(self.dyn_kwargs.as_const())
466 return filter(obj, *args, **kwargs)
472 """{{ foo is lower }}"""
473 fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
478 fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
481 obj = self.node.as_const()
483 # don't evaluate context functions
484 args = [x.as_const() for x in self.args]
485 if type(obj) is FunctionType:
486 if getattr(obj, 'contextfunction', False):
488 elif obj.environmentfunction:
489 args.insert(0, self.environment)
491 kwargs = dict(x.as_const() for x in self.kwargs)
492 if self.dyn_args is not None:
494 args.extend(self.dyn_args.as_const())
497 if self.dyn_kwargs is not None:
499 kwargs.update(self.dyn_kwargs.as_const())
503 return obj(*args, **kwargs)
508 class Subscript(Expr):
509 """{{ foo.bar }} and {{ foo['bar'] }} etc."""
510 fields = ('node', 'arg', 'ctx')
513 if self.ctx != 'load':
516 return self.environment.subscribe(self.node.as_const(),
521 def can_assign(self):
527 fields = ('start', 'stop', 'step')
533 return obj.as_const()
534 return slice(const(self.start), const(self.stop), const(self.step))
538 """For {{ foo ~ bar }}. Concatenates strings."""
542 return ''.join(unicode(x.as_const()) for x in self.nodes)
546 """{{ foo == bar }}, {{ foo >= bar }} etc."""
547 fields = ('expr', 'ops')
550 result = value = self.expr.as_const()
553 new_value = op.expr.as_const()
554 result = _cmpop_to_func[op.op](value, new_value)
561 class Operand(Helper):
562 """Operator + expression."""
563 fields = ('op', 'expr')
567 """{{ foo * bar }}"""
572 """{{ foo / bar }}"""
576 class FloorDiv(BinExpr):
577 """{{ foo // bar }}"""
582 """{{ foo + bar }}"""
587 """{{ foo - bar }}"""
592 """{{ foo % bar }}"""
597 """{{ foo ** bar }}"""
602 """{{ foo and bar }}"""
606 return self.left.as_const() and self.right.as_const()
610 """{{ foo or bar }}"""
614 return self.left.as_const() or self.right.as_const()
617 class Not(UnaryExpr):
622 class Neg(UnaryExpr):
627 class Pos(UnaryExpr):