From: Armin Ronacher Date: Mon, 20 May 2013 08:26:57 +0000 (+0100) Subject: Documented loop.depth and added loop.depth0. X-Git-Tag: 2.7~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=568352e07d74cb4f333d47ae054de3a2991b97ba;p=thirdparty%2Fjinja.git Documented loop.depth and added loop.depth0. --- diff --git a/CHANGES b/CHANGES index d45f78cc..7dac0165 100644 --- a/CHANGES +++ b/CHANGES @@ -28,6 +28,8 @@ Version 2.7 of blocks. - Added `map`, `select`, `reject`, `selectattr` and `rejectattr` filters. +- Added support for `loop.depth` to figure out how deep inside a recursive + loop the code is. Version 2.6 ----------- diff --git a/docs/templates.rst b/docs/templates.rst index 6bc6e04a..e0a19fa3 100644 --- a/docs/templates.rst +++ b/docs/templates.rst @@ -576,6 +576,12 @@ Inside of a for-loop block you can access some special variables: | `loop.cycle` | A helper function to cycle between a list of | | | sequences. See the explanation below. | +-----------------------+---------------------------------------------------+ +| `loop.depth` | Indicates how deep in deep in a recursive loop | +| | the rendering currently is. Starts at level 1 | ++-----------------------+---------------------------------------------------+ +| `loop.depth0 | Indicates how deep in deep in a recursive loop | +| | the rendering currently is. Starts at level 0 | ++-----------------------+---------------------------------------------------+ Within a for-loop, it's possible to cycle among a list of strings/variables each time through the loop by using the special `loop.cycle` helper:: diff --git a/jinja2/compiler.py b/jinja2/compiler.py index 7a42c6d4..d9d7ef97 100644 --- a/jinja2/compiler.py +++ b/jinja2/compiler.py @@ -1066,7 +1066,7 @@ class CodeGenerator(NodeVisitor): # otherwise we set up a buffer and add a function def else: - self.writeline('def loop(reciter, loop_render_func):', node) + self.writeline('def loop(reciter, loop_render_func, depth=0):', node) self.indent() self.buffer(loop_frame) aliases = {} @@ -1125,7 +1125,7 @@ class CodeGenerator(NodeVisitor): self.visit(node.iter, loop_frame) if node.recursive: - self.write(', recurse=loop_render_func):') + self.write(', loop_render_func, depth):') else: self.write(extended_loop and '):' or ':') diff --git a/jinja2/runtime.py b/jinja2/runtime.py index 38a86974..d27ca537 100644 --- a/jinja2/runtime.py +++ b/jinja2/runtime.py @@ -280,11 +280,12 @@ class BlockReference(object): class LoopContext(object): """A loop context for dynamic iteration.""" - def __init__(self, iterable, recurse=None): + def __init__(self, iterable, recurse=None, depth0=0): self._iterator = iter(iterable) self._recurse = recurse self._after = self._safe_next() self.index0 = -1 + self.depth0 = depth0 # try to get the length of the iterable early. This must be done # here because there are some broken iterators around where there @@ -306,6 +307,7 @@ class LoopContext(object): index = property(lambda x: x.index0 + 1) revindex = property(lambda x: x.length - x.index0) revindex0 = property(lambda x: x.length - x.index) + depth = property(lambda x: x.depth0 + 1) def __len__(self): return self.length @@ -324,7 +326,7 @@ class LoopContext(object): if self._recurse is None: raise TypeError('Tried to call non recursive loop. Maybe you ' "forgot the 'recursive' modifier.") - return self._recurse(iterable, self._recurse) + return self._recurse(iterable, self._recurse, self.depth0 + 1) # a nifty trick to enhance the error message if someone tried to call # the the loop without or with too many arguments. diff --git a/jinja2/testsuite/core_tags.py b/jinja2/testsuite/core_tags.py index 409a5791..f1a20fd4 100644 --- a/jinja2/testsuite/core_tags.py +++ b/jinja2/testsuite/core_tags.py @@ -85,6 +85,26 @@ class ForLoopTestCase(JinjaTestCase): dict(a=3, b=[dict(a='a')]) ]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]' + def test_recursive_depth0(self): + tmpl = env.from_string('''{% for item in seq recursive -%} + [{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] + {%- endfor %}''') + self.assertEqual(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')]) + ]), '[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]') + + def test_recursive_depth(self): + tmpl = env.from_string('''{% for item in seq recursive -%} + [{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}] + {%- endfor %}''') + self.assertEqual(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:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]') + def test_looploop(self): tmpl = env.from_string('''{% for row in table %} {%- set rowloop = loop -%}