Permalink
Browse files

Calls to functions in templates are now intercepted for StopIteration.

Improved performance of macro call slightly.

--HG--
branch : trunk
  • Loading branch information...
mitsuhiko committed Jun 5, 2010
1 parent f60232d commit 3351a93bf752825a15acdbcc37719cbee63718ef
Showing with 28 additions and 11 deletions.
  1. +20 −11 jinja2/runtime.py
  2. +8 −0 jinja2/testsuite/api.py
View
@@ -179,7 +179,12 @@ def call(__self, __obj, *args, **kwargs):
args = (__self.eval_ctx,) + args
elif getattr(__obj, 'environmentfunction', 0):
args = (__self.environment,) + args
- return __obj(*args, **kwargs)
+ try:
+ return __obj(*args, **kwargs)
+ except StopIteration:
+ return __self.environment.undefined('value was undefined because '
+ 'a callable raised a '
+ 'StopIteration exception')
def derived(self, locals=None):
"""Internal helper function to create a derived context."""
@@ -345,7 +350,7 @@ def next(self):
class Macro(object):
- """Wraps a macro."""
+ """Wraps a macro function."""
def __init__(self, environment, func, name, arguments, defaults,
catch_kwargs, catch_varargs, caller):
@@ -361,20 +366,24 @@ def __init__(self, environment, func, name, arguments, defaults,
@internalcode
def __call__(self, *args, **kwargs):
- arguments = []
- for idx, name in enumerate(self.arguments):
- try:
- value = args[idx]
- except:
+ # try to consume the positional arguments
+ arguments = list(args[:self._argument_count])
+ off = len(arguments)
+
+ # if the number of arguments consumed is not the number of
+ # arguments expected we start filling in keyword arguments
+ # and defaults.
+ if off != self._argument_count:
+ for idx, name in enumerate(self.arguments[len(arguments):]):
try:
value = kwargs.pop(name)
- except:
+ except KeyError:
try:
- value = self.defaults[idx - self._argument_count]
- except:
+ value = self.defaults[idx - self._argument_count + off]
+ except IndexError:
value = self._environment.undefined(
'parameter %r was not provided' % name, name=name)
- arguments.append(value)
+ arguments.append(value)
# it's important that the order of these arguments does not change
# if not also changed in the compiler's `function_scoping` method.
View
@@ -172,6 +172,14 @@ def test_streaming_behavior(self):
class UndefinedTestCase(JinjaTestCase):
+ def test_stopiteration_is_undefined(self):
+ def test():
+ raise StopIteration()
+ t = Template('A{{ test() }}B')
+ assert t.render(test=test) == 'AB'
+ t = Template('A{{ test().missingattribute }}B')
+ self.assert_raises(UndefinedError, t.render, test=test)
+
def test_default_undefined(self):
env = Environment(undefined=Undefined)
self.assert_equal(env.from_string('{{ missing }}').render(), u'')

0 comments on commit 3351a93

Please sign in to comment.