X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=scripts%2Fjinja2%2Fruntime.py;h=a4a47a284ed4a51ec9e54ae9b439682884e1905c;hb=ce4fdd2c9f1702dab8def3196226e8f6b66caf82;hp=be5b09a02e71febc499749785e00f5450420ec12;hpb=1287307f6dc3b1895a01b9d649ce1b014158435a;p=libfirm diff --git a/scripts/jinja2/runtime.py b/scripts/jinja2/runtime.py index be5b09a02..a4a47a284 100644 --- a/scripts/jinja2/runtime.py +++ b/scripts/jinja2/runtime.py @@ -8,10 +8,10 @@ :copyright: (c) 2010 by the Jinja Team. :license: BSD. """ -import sys from itertools import chain, imap +from jinja2.nodes import EvalContext, _context_function_types from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \ - concat, MethodType, FunctionType, internalcode, next + concat, internalcode, next, object_type_repr from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ TemplateNotFound @@ -19,18 +19,17 @@ from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ # these variables are exported to the template runtime __all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup', 'TemplateRuntimeError', 'missing', 'concat', 'escape', - 'markup_join', 'unicode_join', 'to_string', + 'markup_join', 'unicode_join', 'to_string', 'identity', 'TemplateNotFound'] - -#: the types we support for context functions -_context_function_types = (FunctionType, MethodType) - #: the name of the function that is used to convert something into #: a string. 2to3 will adopt that automatically and the generated #: code can take advantage of it. to_string = unicode +#: the identity function. Useful for certain things in the environment +identity = lambda x: x + def markup_join(seq): """Concatenation that escapes if necessary and converts to unicode.""" @@ -76,8 +75,6 @@ class TemplateReference(object): def __getitem__(self, name): blocks = self.__context.blocks[name] - wrap = self.__context.environment.autoescape and \ - Markup or (lambda x: x) return BlockReference(name, self.__context, blocks, 0) def __repr__(self): @@ -106,13 +103,14 @@ class Context(object): method that doesn't fail with a `KeyError` but returns an :class:`Undefined` object for missing variables. """ - __slots__ = ('parent', 'vars', 'environment', 'exported_vars', 'name', - 'blocks', '__weakref__') + __slots__ = ('parent', 'vars', 'environment', 'eval_ctx', 'exported_vars', + 'name', 'blocks', '__weakref__') def __init__(self, environment, parent, name, blocks): self.parent = parent self.vars = {} self.environment = environment + self.eval_ctx = EvalContext(self.environment, name) self.exported_vars = set() self.name = name @@ -174,14 +172,23 @@ class Context(object): if isinstance(__obj, _context_function_types): if getattr(__obj, 'contextfunction', 0): args = (__self,) + args + elif getattr(__obj, 'evalcontextfunction', 0): + 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.""" context = new_context(self.environment, self.name, {}, self.parent, True, None, locals) + context.vars.update(self.vars) + context.eval_ctx = self.eval_ctx context.blocks.update((k, list(v)) for k, v in self.blocks.iteritems()) return context @@ -252,7 +259,7 @@ class BlockReference(object): @internalcode def __call__(self): rv = concat(self._stack[self._depth](self._context)) - if self._context.environment.autoescape: + if self._context.eval_ctx.autoescape: rv = Markup(rv) return rv @@ -301,7 +308,8 @@ class LoopContext(object): # 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 + __call__ = loop + del loop @property def length(self): @@ -340,7 +348,7 @@ class LoopContextIterator(object): class Macro(object): - """Wraps a macro.""" + """Wraps a macro function.""" def __init__(self, environment, func, name, arguments, defaults, catch_kwargs, catch_varargs, caller): @@ -356,20 +364,24 @@ class Macro(object): @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. @@ -416,7 +428,7 @@ class Undefined(object): __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name', '_undefined_exception') - def __init__(self, hint=None, obj=None, name=None, exc=UndefinedError): + def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): self._undefined_hint = hint self._undefined_obj = obj self._undefined_name = name @@ -428,27 +440,33 @@ class Undefined(object): `UndefinedError` on call. """ if self._undefined_hint is None: - if self._undefined_obj is None: + if self._undefined_obj is missing: hint = '%r is undefined' % self._undefined_name elif not isinstance(self._undefined_name, basestring): - hint = '%r object has no element %r' % ( - self._undefined_obj.__class__.__name__, + hint = '%s has no element %r' % ( + object_type_repr(self._undefined_obj), self._undefined_name ) else: - hint = '%r object has no attribute %r' % ( - self._undefined_obj.__class__.__name__, + hint = '%r has no attribute %r' % ( + object_type_repr(self._undefined_obj), self._undefined_name ) else: hint = self._undefined_hint raise self._undefined_exception(hint) + @internalcode + def __getattr__(self, name): + if name[:2] == '__': + raise AttributeError(name) + return self._fail_with_undefined_error() + __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \ __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \ __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \ - __getattr__ = __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = \ - __int__ = __float__ = __complex__ = __pow__ = __rpow__ = \ + __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \ + __float__ = __complex__ = __pow__ = __rpow__ = \ _fail_with_undefined_error def __str__(self): @@ -492,10 +510,10 @@ class DebugUndefined(Undefined): def __unicode__(self): if self._undefined_hint is None: - if self._undefined_obj is None: + if self._undefined_obj is missing: return u'{{ %s }}' % self._undefined_name return '{{ no such element: %s[%r] }}' % ( - self._undefined_obj.__class__.__name__, + object_type_repr(self._undefined_obj), self._undefined_name ) return u'{{ undefined value printed: %s }}' % self._undefined_hint @@ -522,7 +540,7 @@ class StrictUndefined(Undefined): """ __slots__ = () __iter__ = __unicode__ = __str__ = __len__ = __nonzero__ = __eq__ = \ - __ne__ = Undefined._fail_with_undefined_error + __ne__ = __bool__ = Undefined._fail_with_undefined_error # remove remaining slots attributes, after the metaclass did the magic they