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
-----------
| `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::
# 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 = {}
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 ':')
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
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
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.
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 -%}