summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Ronacher <armin.ronacher@active-4.com>2013-05-20 09:26:57 +0100
committerArmin Ronacher <armin.ronacher@active-4.com>2013-05-20 09:26:57 +0100
commit568352e07d74cb4f333d47ae054de3a2991b97ba (patch)
tree1443ddb9d161a701936a7cce417d993cc3ada61d
parentdcd0cb73120e2d924e7064933cefd3246f3cfffa (diff)
downloadjinja2-568352e07d74cb4f333d47ae054de3a2991b97ba.tar.gz
Documented loop.depth and added loop.depth0.
-rw-r--r--CHANGES2
-rw-r--r--docs/templates.rst6
-rw-r--r--jinja2/compiler.py4
-rw-r--r--jinja2/runtime.py6
-rw-r--r--jinja2/testsuite/core_tags.py20
5 files changed, 34 insertions, 4 deletions
diff --git a/CHANGES b/CHANGES
index d45f78c..7dac016 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 6bc6e04..e0a19fa 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 7a42c6d..d9d7ef9 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 38a8697..d27ca53 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 409a579..f1a20fd 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 -%}