added unittest for recursive for loop
authorArmin Ronacher <armin.ronacher@active-4.com>
Sun, 11 May 2008 21:42:19 +0000 (23:42 +0200)
committerArmin Ronacher <armin.ronacher@active-4.com>
Sun, 11 May 2008 21:42:19 +0000 (23:42 +0200)
--HG--
branch : trunk

jinja2/compiler.py
jinja2/runtime.py
tests/test_forloop.py

index 4716de194d8d23dcb1d72b44cba2b575e2f3a5e5..cf0f4a545063d797554d4dad0a6018f44e6985b4 100644 (file)
@@ -534,7 +534,7 @@ class CodeGenerator(NodeVisitor):
             raise TemplateAssertionError('It\'s not possible to set and '
                                          'access variables derived from '
                                          'an outer scope! (affects: %s' %
-                                         vars, node.lineno, self.name)
+                                         vars, node.lineno, self.filename)
 
         # remove variables from a closure from the frame's undeclared
         # identifiers.
@@ -585,7 +585,7 @@ class CodeGenerator(NodeVisitor):
             if block.name in self.blocks:
                 raise TemplateAssertionError('block %r defined twice' %
                                              block.name, block.lineno,
-                                             self.name)
+                                             self.filename)
             self.blocks[block.name] = block
 
         # find all imports and import them
@@ -601,7 +601,7 @@ class CodeGenerator(NodeVisitor):
                     self.writeline('import %s as %s' % (imp, alias))
 
         # add the load name
-        self.writeline('name = %r' % self.name)
+        self.writeline('name = %r' % self.filename)
 
         # generate the root render function.
         self.writeline('def root(context, environment=environment):', extra=1)
@@ -688,7 +688,7 @@ class CodeGenerator(NodeVisitor):
         if not frame.toplevel:
             raise TemplateAssertionError('cannot use extend from a non '
                                          'top-level scope', node.lineno,
-                                         self.name)
+                                         self.filename)
 
         # if the number of extends statements in general is zero so
         # far, we don't have to add a check if something extended
index d734182c3450abafbbcd4681cd123fa9eed4f10e..2605717c2dd889b1ddd15b0a235757782d281ee9 100644 (file)
@@ -205,12 +205,16 @@ class LoopContext(object):
     def __iter__(self):
         return self
 
-    def __call__(self, iterable):
+    def loop(self, iterable):
         if self._recurse is None:
             raise TypeError('Tried to call non recursive loop.  Maybe you '
-                            'forgot the "recursive" keyword.')
+                            "forgot the 'recursive' modifier.")
         return self._recurse(iterable, self._recurse)
 
+    # a nifty trick to enhance the error message if someone tried to call
+    # the the loop without or with too many arguments.
+    __call__ = loop; del loop
+
     def next(self):
         self.index0 += 1
         return self._next(), self
index dd254945bd6090c52d05b1d8877b7f2f745acb05..9f9020acc9c1accba86ef2a83c5f989c1127d3dc 100644 (file)
@@ -21,6 +21,9 @@ CYCLING = '''{% for item in seq %}{{ loop.cycle('<1>', '<2>') }}{% endfor %}\
 SCOPE = '''{% for item in seq %}{% endfor %}{{ item }}'''
 VARLEN = '''{% for item in iter %}{{ item }}{% endfor %}'''
 NONITER = '''{% for item in none %}...{% endfor %}'''
+RECURSIVE = '''{% for item in seq recursive -%}
+    [{{ item.a }}{% if item.b %}[{{ loop(item.b) }}]{% endif %}]
+{%- endfor %}'''
 
 
 def test_simple(env):
@@ -79,3 +82,12 @@ def test_varlen(env):
 def test_noniter(env):
     tmpl = env.from_string(NONITER)
     raises(TypeError, tmpl.render)
+
+
+def test_recursive(env):
+    tmpl = env.from_string(RECURSIVE)
+    assert 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]]][2[[1][2]]][3[[a]]]'