| 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 |