From cb1f239ab9d3ff0a8650599caa42e29862199ccb Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Wed, 11 Apr 2007 22:38:17 +0200 Subject: [PATCH] [svn] constants are now immutable in jinja --HG-- branch : trunk --- docs/src/designerdoc.txt | 26 ++++++++++++++++- jinja/translators/python.py | 58 ++++++++++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/docs/src/designerdoc.txt b/docs/src/designerdoc.txt index b8d7904..3443aa4 100644 --- a/docs/src/designerdoc.txt +++ b/docs/src/designerdoc.txt @@ -382,7 +382,7 @@ can use expressions. In expressions you can use any of the following operators: ``{{ 1 / 2 }}`` would return ``0.5``. ``//`` divide the left operand by the right one and return a truncated integer result: ``{{ 20 // 7 }}`` is ``2``. (*new in - Jinja 1.1*) + Jinja 1.1*) ``*`` multiply the left operand with the right one. ``{{ 2 * 2 }}`` would return ``4``. ``**`` raise the left operand to the power of the right @@ -786,6 +786,30 @@ means that they won't raise an error for several releases but yield warnings on the application side. But it's very unlikely that new keywords will be added. +Global Constants +================ + +Jinja provides some special variables which cannot be overridden in templates. +Those are not affected by the variable lookup: + + `_`, `true`, `false`, `none`, `undefined` + +You cannot use those names for your own variables or macros. It's however no +problem to have blocks with that name. + +**Notice** due to a bug in Jinja 1.0 it was possible to override `_`, `true`, +`false`, `none` and `undefined` from the template by either using `{% set %}` +or in a for loop. While overriding `true`, `false` etc just caused nothing +overriding the translation marker `_` would crash the translation interface. +If you want to use `_` for unpacking in for loops (eg. skipping items) you +have to give it a proper name: + +.. sourcecode:: jinja + + {% for key, ignore in mydict|dictsort %} + {{ key|e }} + {% endfor %} + Whitespace ========== diff --git a/jinja/translators/python.py b/jinja/translators/python.py index d58537f..cfe4d34 100644 --- a/jinja/translators/python.py +++ b/jinja/translators/python.py @@ -180,7 +180,7 @@ class PythonTranslator(Translator): nodes.Trans: self.handle_trans, # python nodes ast.Name: self.handle_name, - ast.AssName: self.handle_name, + ast.AssName: self.handle_assign_name, ast.Compare: self.handle_compare, ast.Const: self.handle_const, ast.Subscript: self.handle_subscript, @@ -269,17 +269,20 @@ class PythonTranslator(Translator): raise TemplateSyntaxError('invalid filter. filter must ' 'be a hardcoded function name ' 'from the filter namespace', - n.lineno) + n.lineno, + n.filename) args = [] for arg in n.args: if arg.__class__ is ast.Keyword: raise TemplateSyntaxError('keyword arguments for ' 'filters are not supported.', - n.lineno) + n.lineno, + n.filename) args.append(self.handle_node(arg)) if n.star_args is not None or n.dstar_args is not None: raise TemplateSyntaxError('*args / **kwargs is not supported ' - 'for filters', n.lineno) + 'for filters', n.lineno, + n.filename) filters.append('(%r, %s)' % ( n.node.name, _to_tuple(args) @@ -290,7 +293,7 @@ class PythonTranslator(Translator): raise TemplateSyntaxError('invalid filter. filter must be a ' 'hardcoded function name from the ' 'filter namespace', - n.lineno) + n.lineno, n.filename) return 'apply_filters(%s, context, %s)' % (s, _to_tuple(filters)) def handle_node(self, node): @@ -304,7 +307,7 @@ class PythonTranslator(Translator): elif node.__class__ in self.unsupported: raise TemplateSyntaxError('unsupported syntax element %r found.' % self.unsupported[node.__class__], - node.lineno) + node.lineno, node.filename) else: raise AssertionError('unhandled node %r' % node.__class__) return out @@ -624,6 +627,16 @@ class PythonTranslator(Translator): """ Handle macro declarations. """ + # sanity check for name + if node.name == '_' or \ + node.name in self.constants: + raise TemplateSyntaxError('cannot override %r' % node.name, + node.lineno, node.filename) + if node.name in self.constants: + raise TemplateSyntaxError('you cannot name a macro %r', + node.lineno, + node.filename) + buf = [] write = lambda x: buf.append(self.indent(x)) @@ -662,6 +675,9 @@ class PythonTranslator(Translator): """ Handle variable assignments. """ + if node.name == '_' or node.name in self.constants: + raise TemplateSyntaxError('cannot override %r' % node.name, + node.lineno, node.filename) return self.indent(self.nodeinfo(node)) + '\n' + \ self.indent('context[%r] = %s' % ( node.name, @@ -744,6 +760,16 @@ class PythonTranslator(Translator): # -- python nodes + def handle_assign_name(self, node): + """ + Handle name assignments. + """ + if node.name == '_' or \ + node.name in self.constants: + raise TemplateSyntaxError('cannot override %r' % node.name, + node.lineno, node.filename) + return 'context[%r]' % node.name + def handle_name(self, node): """ Handle name assignments and name retreivement. @@ -765,7 +791,8 @@ class PythonTranslator(Translator): if node.ops[0][0] in ('is', 'is not'): if len(node.ops) > 1: raise TemplateSyntaxError('is operator must not be chained', - node.lineno) + node.lineno, + node.filename) elif node.ops[0][1].__class__ is ast.Name: args = [] name = node.ops[0][1].name @@ -775,21 +802,25 @@ class PythonTranslator(Translator): raise TemplateSyntaxError('invalid test. test must ' 'be a hardcoded function name ' 'from the test namespace', - n.lineno) + n.lineno, + n.filename) name = n.node.name args = [] for arg in n.args: if arg.__class__ is ast.Keyword: raise TemplateSyntaxError('keyword arguments for ' 'tests are not supported.', - n.lineno) + n.lineno, + n.filename) args.append(self.handle_node(arg)) if n.star_args is not None or n.dstar_args is not None: raise TemplateSyntaxError('*args / **kwargs is not supported ' - 'for tests', n.lineno) + 'for tests', n.lineno, + n.filename) else: raise TemplateSyntaxError('is operator requires a test name' - ' as operand', node.lineno) + ' as operand', node.lineno, + node.filename) return 'perform_test(context, %r, %s, %s, %s)' % ( name, _to_tuple(args), @@ -803,7 +834,7 @@ class PythonTranslator(Translator): for op, n in node.ops: if op in ('is', 'is not'): raise TemplateSyntaxError('is operator must not be chained', - node.lineno) + node.lineno, node.filename) buf.append(op) buf.append(self.handle_node(n)) return ' '.join(buf) @@ -820,7 +851,8 @@ class PythonTranslator(Translator): """ if len(node.subs) != 1: raise TemplateSyntaxError('attribute access requires one argument', - node.lineno) + node.lineno, + node.filename) assert node.flags != 'OP_DELETE', 'wtf? do we support that?' if node.subs[0].__class__ is ast.Sliceobj: return '%s[%s]' % ( -- 2.26.2