OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """ | 2 """ |
3 jinja2.nodes | 3 jinja2.nodes |
4 ~~~~~~~~~~~~ | 4 ~~~~~~~~~~~~ |
5 | 5 |
6 This module implements additional nodes derived from the ast base node. | 6 This module implements additional nodes derived from the ast base node. |
7 | 7 |
8 It also provides some node tree helper functions like `in_lineno` and | 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 | 9 `get_nodes` used by the parser and translator in order to normalize |
10 python and jinja nodes. | 10 python and jinja nodes. |
11 | 11 |
12 :copyright: (c) 2010 by the Jinja Team. | 12 :copyright: (c) 2010 by the Jinja Team. |
13 :license: BSD, see LICENSE for more details. | 13 :license: BSD, see LICENSE for more details. |
14 """ | 14 """ |
15 import operator | 15 import operator |
16 from itertools import chain, izip | 16 |
17 from collections import deque | 17 from collections import deque |
18 from jinja2.utils import Markup, MethodType, FunctionType | 18 from jinja2.utils import Markup |
| 19 from jinja2._compat import next, izip, with_metaclass, text_type, \ |
| 20 method_type, function_type |
19 | 21 |
20 | 22 |
21 #: the types we support for context functions | 23 #: the types we support for context functions |
22 _context_function_types = (FunctionType, MethodType) | 24 _context_function_types = (function_type, method_type) |
23 | 25 |
24 | 26 |
25 _binop_to_func = { | 27 _binop_to_func = { |
26 '*': operator.mul, | 28 '*': operator.mul, |
27 '/': operator.truediv, | 29 '/': operator.truediv, |
28 '//': operator.floordiv, | 30 '//': operator.floordiv, |
29 '**': operator.pow, | 31 '**': operator.pow, |
30 '%': operator.mod, | 32 '%': operator.mod, |
31 '+': operator.add, | 33 '+': operator.add, |
32 '-': operator.sub | 34 '-': operator.sub |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 def get_eval_context(node, ctx): | 97 def get_eval_context(node, ctx): |
96 if ctx is None: | 98 if ctx is None: |
97 if node.environment is None: | 99 if node.environment is None: |
98 raise RuntimeError('if no eval context is passed, the ' | 100 raise RuntimeError('if no eval context is passed, the ' |
99 'node must have an attached ' | 101 'node must have an attached ' |
100 'environment.') | 102 'environment.') |
101 return EvalContext(node.environment) | 103 return EvalContext(node.environment) |
102 return ctx | 104 return ctx |
103 | 105 |
104 | 106 |
105 class Node(object): | 107 class Node(with_metaclass(NodeType, object)): |
106 """Baseclass for all Jinja2 nodes. There are a number of nodes available | 108 """Baseclass for all Jinja2 nodes. There are a number of nodes available |
107 of different types. There are three major types: | 109 of different types. There are four major types: |
108 | 110 |
109 - :class:`Stmt`: statements | 111 - :class:`Stmt`: statements |
110 - :class:`Expr`: expressions | 112 - :class:`Expr`: expressions |
111 - :class:`Helper`: helper nodes | 113 - :class:`Helper`: helper nodes |
112 - :class:`Template`: the outermost wrapper node | 114 - :class:`Template`: the outermost wrapper node |
113 | 115 |
114 All nodes have fields and attributes. Fields may be other nodes, lists, | 116 All nodes have fields and attributes. Fields may be other nodes, lists, |
115 or arbitrary values. Fields are passed to the constructor as regular | 117 or arbitrary values. Fields are passed to the constructor as regular |
116 positional arguments, attributes as keyword arguments. Each node has | 118 positional arguments, attributes as keyword arguments. Each node has |
117 two attributes: `lineno` (the line number of the node) and `environment`. | 119 two attributes: `lineno` (the line number of the node) and `environment`. |
118 The `environment` attribute is set at the end of the parsing process for | 120 The `environment` attribute is set at the end of the parsing process for |
119 all nodes automatically. | 121 all nodes automatically. |
120 """ | 122 """ |
121 __metaclass__ = NodeType | |
122 fields = () | 123 fields = () |
123 attributes = ('lineno', 'environment') | 124 attributes = ('lineno', 'environment') |
124 abstract = True | 125 abstract = True |
125 | 126 |
126 def __init__(self, *fields, **attributes): | 127 def __init__(self, *fields, **attributes): |
127 if self.abstract: | 128 if self.abstract: |
128 raise TypeError('abstract nodes are not instanciable') | 129 raise TypeError('abstract nodes are not instanciable') |
129 if fields: | 130 if fields: |
130 if len(fields) != len(self.fields): | 131 if len(fields) != len(self.fields): |
131 if not self.fields: | 132 if not self.fields: |
132 raise TypeError('%r takes 0 arguments' % | 133 raise TypeError('%r takes 0 arguments' % |
133 self.__class__.__name__) | 134 self.__class__.__name__) |
134 raise TypeError('%r takes 0 or %d argument%s' % ( | 135 raise TypeError('%r takes 0 or %d argument%s' % ( |
135 self.__class__.__name__, | 136 self.__class__.__name__, |
136 len(self.fields), | 137 len(self.fields), |
137 len(self.fields) != 1 and 's' or '' | 138 len(self.fields) != 1 and 's' or '' |
138 )) | 139 )) |
139 for name, arg in izip(self.fields, fields): | 140 for name, arg in izip(self.fields, fields): |
140 setattr(self, name, arg) | 141 setattr(self, name, arg) |
141 for attr in self.attributes: | 142 for attr in self.attributes: |
142 setattr(self, attr, attributes.pop(attr, None)) | 143 setattr(self, attr, attributes.pop(attr, None)) |
143 if attributes: | 144 if attributes: |
144 raise TypeError('unknown attribute %r' % | 145 raise TypeError('unknown attribute %r' % |
145 iter(attributes).next()) | 146 next(iter(attributes))) |
146 | 147 |
147 def iter_fields(self, exclude=None, only=None): | 148 def iter_fields(self, exclude=None, only=None): |
148 """This method iterates over all fields that are defined and yields | 149 """This method iterates over all fields that are defined and yields |
149 ``(key, value)`` tuples. Per default all fields are returned, but | 150 ``(key, value)`` tuples. Per default all fields are returned, but |
150 it's possible to limit that to some fields by providing the `only` | 151 it's possible to limit that to some fields by providing the `only` |
151 parameter or to exclude some using the `exclude` parameter. Both | 152 parameter or to exclude some using the `exclude` parameter. Both |
152 should be sets or tuples of field names. | 153 should be sets or tuples of field names. |
153 """ | 154 """ |
154 for name in self.fields: | 155 for name in self.fields: |
155 if (exclude is only is None) or \ | 156 if (exclude is only is None) or \ |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 todo.extend(node.iter_child_nodes()) | 225 todo.extend(node.iter_child_nodes()) |
225 return self | 226 return self |
226 | 227 |
227 def __eq__(self, other): | 228 def __eq__(self, other): |
228 return type(self) is type(other) and \ | 229 return type(self) is type(other) and \ |
229 tuple(self.iter_fields()) == tuple(other.iter_fields()) | 230 tuple(self.iter_fields()) == tuple(other.iter_fields()) |
230 | 231 |
231 def __ne__(self, other): | 232 def __ne__(self, other): |
232 return not self.__eq__(other) | 233 return not self.__eq__(other) |
233 | 234 |
| 235 # Restore Python 2 hashing behavior on Python 3 |
| 236 __hash__ = object.__hash__ |
| 237 |
234 def __repr__(self): | 238 def __repr__(self): |
235 return '%s(%s)' % ( | 239 return '%s(%s)' % ( |
236 self.__class__.__name__, | 240 self.__class__.__name__, |
237 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for | 241 ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for |
238 arg in self.fields) | 242 arg in self.fields) |
239 ) | 243 ) |
240 | 244 |
241 | 245 |
242 class Stmt(Node): | 246 class Stmt(Node): |
243 """Base node for all statements.""" | 247 """Base node for all statements.""" |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 | 437 |
434 def as_const(self, eval_ctx=None): | 438 def as_const(self, eval_ctx=None): |
435 return self.value | 439 return self.value |
436 | 440 |
437 @classmethod | 441 @classmethod |
438 def from_untrusted(cls, value, lineno=None, environment=None): | 442 def from_untrusted(cls, value, lineno=None, environment=None): |
439 """Return a const object if the value is representable as | 443 """Return a const object if the value is representable as |
440 constant value in the generated code, otherwise it will raise | 444 constant value in the generated code, otherwise it will raise |
441 an `Impossible` exception. | 445 an `Impossible` exception. |
442 """ | 446 """ |
443 from compiler import has_safe_repr | 447 from .compiler import has_safe_repr |
444 if not has_safe_repr(value): | 448 if not has_safe_repr(value): |
445 raise Impossible() | 449 raise Impossible() |
446 return cls(value, lineno=lineno, environment=environment) | 450 return cls(value, lineno=lineno, environment=environment) |
447 | 451 |
448 | 452 |
449 class TemplateData(Literal): | 453 class TemplateData(Literal): |
450 """A constant template string.""" | 454 """A constant template string.""" |
451 fields = ('data',) | 455 fields = ('data',) |
452 | 456 |
453 def as_const(self, eval_ctx=None): | 457 def as_const(self, eval_ctx=None): |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
680 | 684 |
681 | 685 |
682 class Concat(Expr): | 686 class Concat(Expr): |
683 """Concatenates the list of expressions provided after converting them to | 687 """Concatenates the list of expressions provided after converting them to |
684 unicode. | 688 unicode. |
685 """ | 689 """ |
686 fields = ('nodes',) | 690 fields = ('nodes',) |
687 | 691 |
688 def as_const(self, eval_ctx=None): | 692 def as_const(self, eval_ctx=None): |
689 eval_ctx = get_eval_context(self, eval_ctx) | 693 eval_ctx = get_eval_context(self, eval_ctx) |
690 return ''.join(unicode(x.as_const(eval_ctx)) for x in self.nodes) | 694 return ''.join(text_type(x.as_const(eval_ctx)) for x in self.nodes) |
691 | 695 |
692 | 696 |
693 class Compare(Expr): | 697 class Compare(Expr): |
694 """Compares an expression with some other expressions. `ops` must be a | 698 """Compares an expression with some other expressions. `ops` must be a |
695 list of :class:`Operand`\s. | 699 list of :class:`Operand`\s. |
696 """ | 700 """ |
697 fields = ('expr', 'ops') | 701 fields = ('expr', 'ops') |
698 | 702 |
699 def as_const(self, eval_ctx=None): | 703 def as_const(self, eval_ctx=None): |
700 eval_ctx = get_eval_context(self, eval_ctx) | 704 eval_ctx = get_eval_context(self, eval_ctx) |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
901 :class:`EvalContextModifier` but will only modify the | 905 :class:`EvalContextModifier` but will only modify the |
902 :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`. | 906 :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`. |
903 """ | 907 """ |
904 fields = ('body',) | 908 fields = ('body',) |
905 | 909 |
906 | 910 |
907 # make sure nobody creates custom nodes | 911 # make sure nobody creates custom nodes |
908 def _failing_new(*args, **kwargs): | 912 def _failing_new(*args, **kwargs): |
909 raise TypeError('can\'t create custom node types') | 913 raise TypeError('can\'t create custom node types') |
910 NodeType.__new__ = staticmethod(_failing_new); del _failing_new | 914 NodeType.__new__ = staticmethod(_failing_new); del _failing_new |
OLD | NEW |