Skip to content

Commit 568352e

Browse files
committed
Documented loop.depth and added loop.depth0.
1 parent dcd0cb7 commit 568352e

File tree

5 files changed

+34
-4
lines changed

5 files changed

+34
-4
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Version 2.7
2828
of blocks.
2929
- Added `map`, `select`, `reject`, `selectattr` and `rejectattr`
3030
filters.
31+
- Added support for `loop.depth` to figure out how deep inside a recursive
32+
loop the code is.
3133

3234
Version 2.6
3335
-----------

docs/templates.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,12 @@ Inside of a for-loop block you can access some special variables:
576576
| `loop.cycle` | A helper function to cycle between a list of |
577577
| | sequences. See the explanation below. |
578578
+-----------------------+---------------------------------------------------+
579+
| `loop.depth` | Indicates how deep in deep in a recursive loop |
580+
| | the rendering currently is. Starts at level 1 |
581+
+-----------------------+---------------------------------------------------+
582+
| `loop.depth0 | Indicates how deep in deep in a recursive loop |
583+
| | the rendering currently is. Starts at level 0 |
584+
+-----------------------+---------------------------------------------------+
579585

580586
Within a for-loop, it's possible to cycle among a list of strings/variables
581587
each time through the loop by using the special `loop.cycle` helper::

jinja2/compiler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ def visit_For(self, node, frame):
10661066

10671067
# otherwise we set up a buffer and add a function def
10681068
else:
1069-
self.writeline('def loop(reciter, loop_render_func):', node)
1069+
self.writeline('def loop(reciter, loop_render_func, depth=0):', node)
10701070
self.indent()
10711071
self.buffer(loop_frame)
10721072
aliases = {}
@@ -1125,7 +1125,7 @@ def visit_For(self, node, frame):
11251125
self.visit(node.iter, loop_frame)
11261126

11271127
if node.recursive:
1128-
self.write(', recurse=loop_render_func):')
1128+
self.write(', loop_render_func, depth):')
11291129
else:
11301130
self.write(extended_loop and '):' or ':')
11311131

jinja2/runtime.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,11 +280,12 @@ def __call__(self):
280280
class LoopContext(object):
281281
"""A loop context for dynamic iteration."""
282282

283-
def __init__(self, iterable, recurse=None):
283+
def __init__(self, iterable, recurse=None, depth0=0):
284284
self._iterator = iter(iterable)
285285
self._recurse = recurse
286286
self._after = self._safe_next()
287287
self.index0 = -1
288+
self.depth0 = depth0
288289

289290
# try to get the length of the iterable early. This must be done
290291
# here because there are some broken iterators around where there
@@ -306,6 +307,7 @@ def cycle(self, *args):
306307
index = property(lambda x: x.index0 + 1)
307308
revindex = property(lambda x: x.length - x.index0)
308309
revindex0 = property(lambda x: x.length - x.index)
310+
depth = property(lambda x: x.depth0 + 1)
309311

310312
def __len__(self):
311313
return self.length
@@ -324,7 +326,7 @@ def loop(self, iterable):
324326
if self._recurse is None:
325327
raise TypeError('Tried to call non recursive loop. Maybe you '
326328
"forgot the 'recursive' modifier.")
327-
return self._recurse(iterable, self._recurse)
329+
return self._recurse(iterable, self._recurse, self.depth0 + 1)
328330

329331
# a nifty trick to enhance the error message if someone tried to call
330332
# the the loop without or with too many arguments.

jinja2/testsuite/core_tags.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,26 @@ def test_recursive(self):
8585
dict(a=3, b=[dict(a='a')])
8686
]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]'
8787

88+
def test_recursive_depth0(self):
89+
tmpl = env.from_string('''{% for item in seq recursive -%}
90+
[{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
91+
{%- endfor %}''')
92+
self.assertEqual(tmpl.render(seq=[
93+
dict(a=1, b=[dict(a=1), dict(a=2)]),
94+
dict(a=2, b=[dict(a=1), dict(a=2)]),
95+
dict(a=3, b=[dict(a='a')])
96+
]), '[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]')
97+
98+
def test_recursive_depth(self):
99+
tmpl = env.from_string('''{% for item in seq recursive -%}
100+
[{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
101+
{%- endfor %}''')
102+
self.assertEqual(tmpl.render(seq=[
103+
dict(a=1, b=[dict(a=1), dict(a=2)]),
104+
dict(a=2, b=[dict(a=1), dict(a=2)]),
105+
dict(a=3, b=[dict(a='a')])
106+
]), '[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]')
107+
88108
def test_looploop(self):
89109
tmpl = env.from_string('''{% for row in table %}
90110
{%- set rowloop = loop -%}

0 commit comments

Comments
 (0)