From 66a9344ed58aed5de49504de1b957f51e4c89f8e Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sun, 11 May 2008 23:42:19 +0200 Subject: [PATCH] added unittest for recursive for loop --HG-- branch : trunk --- jinja2/compiler.py | 8 ++++---- jinja2/runtime.py | 8 ++++++-- tests/test_forloop.py | 12 ++++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/jinja2/compiler.py b/jinja2/compiler.py index 4716de1..cf0f4a5 100644 --- a/jinja2/compiler.py +++ b/jinja2/compiler.py @@ -534,7 +534,7 @@ class CodeGenerator(NodeVisitor): raise TemplateAssertionError('It\'s not possible to set and ' 'access variables derived from ' 'an outer scope! (affects: %s' % - vars, node.lineno, self.name) + vars, node.lineno, self.filename) # remove variables from a closure from the frame's undeclared # identifiers. @@ -585,7 +585,7 @@ class CodeGenerator(NodeVisitor): if block.name in self.blocks: raise TemplateAssertionError('block %r defined twice' % block.name, block.lineno, - self.name) + self.filename) self.blocks[block.name] = block # find all imports and import them @@ -601,7 +601,7 @@ class CodeGenerator(NodeVisitor): self.writeline('import %s as %s' % (imp, alias)) # add the load name - self.writeline('name = %r' % self.name) + self.writeline('name = %r' % self.filename) # generate the root render function. self.writeline('def root(context, environment=environment):', extra=1) @@ -688,7 +688,7 @@ class CodeGenerator(NodeVisitor): if not frame.toplevel: raise TemplateAssertionError('cannot use extend from a non ' 'top-level scope', node.lineno, - self.name) + self.filename) # if the number of extends statements in general is zero so # far, we don't have to add a check if something extended diff --git a/jinja2/runtime.py b/jinja2/runtime.py index d734182..2605717 100644 --- a/jinja2/runtime.py +++ b/jinja2/runtime.py @@ -205,12 +205,16 @@ class LoopContext(object): def __iter__(self): return self - def __call__(self, iterable): + def loop(self, iterable): if self._recurse is None: raise TypeError('Tried to call non recursive loop. Maybe you ' - 'forgot the "recursive" keyword.') + "forgot the 'recursive' modifier.") return self._recurse(iterable, self._recurse) + # a nifty trick to enhance the error message if someone tried to call + # the the loop without or with too many arguments. + __call__ = loop; del loop + def next(self): self.index0 += 1 return self._next(), self diff --git a/tests/test_forloop.py b/tests/test_forloop.py index dd25494..9f9020a 100644 --- a/tests/test_forloop.py +++ b/tests/test_forloop.py @@ -21,6 +21,9 @@ CYCLING = '''{% for item in seq %}{{ loop.cycle('<1>', '<2>') }}{% endfor %}\ SCOPE = '''{% for item in seq %}{% endfor %}{{ item }}''' VARLEN = '''{% for item in iter %}{{ item }}{% endfor %}''' NONITER = '''{% for item in none %}...{% endfor %}''' +RECURSIVE = '''{% for item in seq recursive -%} + [{{ item.a }}{% if item.b %}[{{ loop(item.b) }}]{% endif %}] +{%- endfor %}''' def test_simple(env): @@ -79,3 +82,12 @@ def test_varlen(env): def test_noniter(env): tmpl = env.from_string(NONITER) raises(TypeError, tmpl.render) + + +def test_recursive(env): + tmpl = env.from_string(RECURSIVE) + assert tmpl.render(seq=[ + dict(a=1, b=[dict(a=1), dict(a=2)]), + dict(a=2, b=[dict(a=1), dict(a=2)]), + dict(a=3, b=[dict(a='a')]) + ]) == '[1[[1][2]]][2[[1][2]]][3[[a]]]' -- 2.26.2