From 776567cc4e87f26ad57b52bb16c5462a281b4ca3 Mon Sep 17 00:00:00 2001 From: Jason Kotenko Date: Tue, 24 Jan 2012 14:19:08 -0800 Subject: [PATCH] Fixed loop.last to not consume the entire iterator to determine if this is the last iteration of the loop. --- jinja2/runtime.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/jinja2/runtime.py b/jinja2/runtime.py index a4a47a2..c70cb4e 100644 --- a/jinja2/runtime.py +++ b/jinja2/runtime.py @@ -266,10 +266,12 @@ class BlockReference(object): class LoopContext(object): """A loop context for dynamic iteration.""" + End = object() def __init__(self, iterable, recurse=None): self._iterator = iter(iterable) self._recurse = recurse + self._after = self._safe_next() self.index0 = -1 # try to get the length of the iterable early. This must be done @@ -288,7 +290,7 @@ class LoopContext(object): return args[self.index0 % len(args)] first = property(lambda x: x.index0 == 0) - last = property(lambda x: x.index0 + 1 == x.length) + last = property(lambda x: x._after is LoopContext.End) index = property(lambda x: x.index0 + 1) revindex = property(lambda x: x.length - x.index0) revindex0 = property(lambda x: x.length - x.index) @@ -299,6 +301,12 @@ class LoopContext(object): def __iter__(self): return LoopContextIterator(self) + def _safe_next(self): + try: + return next(self._iterator) + except StopIteration: + return self.End + @internalcode def loop(self, iterable): if self._recurse is None: @@ -344,7 +352,11 @@ class LoopContextIterator(object): def next(self): ctx = self.context ctx.index0 += 1 - return next(ctx._iterator), ctx + if ctx._after is LoopContext.End: + raise StopIteration + next_elem = ctx._after + ctx._after = ctx._safe_next() + return next_elem, ctx class Macro(object): -- 2.26.2