Permalink
Browse files

Documented loop.depth and added loop.depth0.

  • Loading branch information...
1 parent dcd0cb7 commit 568352e07d74cb4f333d47ae054de3a2991b97ba @mitsuhiko mitsuhiko committed May 20, 2013
Showing with 34 additions and 4 deletions.
  1. +2 −0 CHANGES
  2. +6 −0 docs/templates.rst
  3. +2 −2 jinja2/compiler.py
  4. +4 −2 jinja2/runtime.py
  5. +20 −0 jinja2/testsuite/core_tags.py
View
2 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
-----------
View
6 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::
View
4 jinja2/compiler.py
@@ -1066,7 +1066,7 @@ def visit_For(self, node, frame):
# 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 @@ def visit_For(self, node, frame):
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 ':')
View
6 jinja2/runtime.py
@@ -280,11 +280,12 @@ def __call__(self):
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 @@ def cycle(self, *args):
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 @@ def loop(self, iterable):
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.
View
20 jinja2/testsuite/core_tags.py
@@ -85,6 +85,26 @@ def test_recursive(self):
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 -%}

0 comments on commit 568352e

Please sign in to comment.