diff options
Diffstat (limited to 'src/jinja2/runtime.py')
-rw-r--r-- | src/jinja2/runtime.py | 305 |
1 files changed, 201 insertions, 104 deletions
diff --git a/src/jinja2/runtime.py b/src/jinja2/runtime.py index 7ee9927..9f4f224 100644 --- a/src/jinja2/runtime.py +++ b/src/jinja2/runtime.py @@ -36,10 +36,23 @@ from .utils import object_type_repr from .utils import soft_unicode # these variables are exported to the template runtime -__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup', - 'TemplateRuntimeError', 'missing', 'concat', 'escape', - 'markup_join', 'unicode_join', 'to_string', 'identity', - 'TemplateNotFound', 'Namespace', 'Undefined'] +__all__ = [ + "LoopContext", + "TemplateReference", + "Macro", + "Markup", + "TemplateRuntimeError", + "missing", + "concat", + "escape", + "markup_join", + "unicode_join", + "to_string", + "identity", + "TemplateNotFound", + "Namespace", + "Undefined", +] #: the name of the function that is used to convert something into #: a string. We can just use the text type here. @@ -58,8 +71,8 @@ def markup_join(seq): iterator = imap(soft_unicode, seq) for arg in iterator: buf.append(arg) - if hasattr(arg, '__html__'): - return Markup(u'').join(chain(buf, iterator)) + if hasattr(arg, "__html__"): + return Markup(u"").join(chain(buf, iterator)) return concat(buf) @@ -68,8 +81,15 @@ def unicode_join(seq): return concat(imap(text_type, seq)) -def new_context(environment, template_name, blocks, vars=None, - shared=None, globals=None, locals=None): +def new_context( + environment, + template_name, + blocks, + vars=None, + shared=None, + globals=None, + locals=None, +): """Internal helper for context creation.""" if vars is None: vars = {} @@ -85,8 +105,7 @@ def new_context(environment, template_name, blocks, vars=None, for key, value in iteritems(locals): if value is not missing: parent[key] = value - return environment.context_class(environment, parent, template_name, - blocks) + return environment.context_class(environment, parent, template_name, blocks) class TemplateReference(object): @@ -100,18 +119,14 @@ class TemplateReference(object): return BlockReference(name, self.__context, blocks, 0) def __repr__(self): - return '<%s %r>' % ( - self.__class__.__name__, - self.__context.name - ) + return "<%s %r>" % (self.__class__.__name__, self.__context.name) def _get_func(x): - return getattr(x, '__func__', x) + return getattr(x, "__func__", x) class ContextMeta(type): - def __new__(cls, name, bases, d): rv = type.__new__(cls, name, bases, d) if bases == (): @@ -124,11 +139,15 @@ class ContextMeta(type): # If we have a changed resolve but no changed default or missing # resolve we invert the call logic. - if resolve is not default_resolve and \ - resolve_or_missing is default_resolve_or_missing: + if ( + resolve is not default_resolve + and resolve_or_missing is default_resolve_or_missing + ): rv._legacy_resolve_mode = True - elif resolve is default_resolve and \ - resolve_or_missing is default_resolve_or_missing: + elif ( + resolve is default_resolve + and resolve_or_missing is default_resolve_or_missing + ): rv._fast_resolve_mode = True return rv @@ -161,6 +180,7 @@ class Context(with_metaclass(ContextMeta)): method that doesn't fail with a `KeyError` but returns an :class:`Undefined` object for missing variables. """ + # XXX: we want to eventually make this be a deprecation warning and # remove it. _legacy_resolve_mode = False @@ -191,9 +211,9 @@ class Context(with_metaclass(ContextMeta)): index = blocks.index(current) + 1 blocks[index] except LookupError: - return self.environment.undefined('there is no parent block ' - 'called %r.' % name, - name='super') + return self.environment.undefined( + "there is no parent block called %r." % name, name="super" + ) return BlockReference(name, self, blocks, index) def get(self, key, default=None): @@ -254,36 +274,41 @@ class Context(with_metaclass(ContextMeta)): __traceback_hide__ = True # noqa # Allow callable classes to take a context - if hasattr(__obj, '__call__'): + if hasattr(__obj, "__call__"): fn = __obj.__call__ - for fn_type in ('contextfunction', - 'evalcontextfunction', - 'environmentfunction'): + for fn_type in ( + "contextfunction", + "evalcontextfunction", + "environmentfunction", + ): if hasattr(fn, fn_type): __obj = fn break if callable(__obj): - if getattr(__obj, 'contextfunction', 0): + if getattr(__obj, "contextfunction", 0): args = (__self,) + args - elif getattr(__obj, 'evalcontextfunction', 0): + elif getattr(__obj, "evalcontextfunction", 0): args = (__self.eval_ctx,) + args - elif getattr(__obj, 'environmentfunction', 0): + elif getattr(__obj, "environmentfunction", 0): args = (__self.environment,) + args try: return __obj(*args, **kwargs) except StopIteration: - return __self.environment.undefined('value was undefined because ' - 'a callable raised a ' - 'StopIteration exception') + 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. This is used in situations where the system needs a new context in the same template that is independent. """ - context = new_context(self.environment, self.name, {}, - self.get_all(), True, None, locals) + context = new_context( + self.environment, self.name, {}, self.get_all(), True, None, locals + ) context.eval_ctx = self.eval_ctx context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) return context @@ -294,15 +319,15 @@ class Context(with_metaclass(ContextMeta)): proxy.__name__ = meth return proxy - keys = _all('keys') - values = _all('values') - items = _all('items') + keys = _all("keys") + values = _all("values") + items = _all("items") # not available on python 3 if PY2: - iterkeys = _all('iterkeys') - itervalues = _all('itervalues') - iteritems = _all('iteritems') + iterkeys = _all("iterkeys") + itervalues = _all("itervalues") + iteritems = _all("iteritems") del _all def __contains__(self, name): @@ -318,10 +343,10 @@ class Context(with_metaclass(ContextMeta)): return item def __repr__(self): - return '<%s %s of %r>' % ( + return "<%s %s of %r>" % ( self.__class__.__name__, repr(self.get_all()), - self.name + self.name, ) @@ -341,11 +366,10 @@ class BlockReference(object): def super(self): """Super the block.""" if self._depth + 1 >= len(self._stack): - return self._context.environment. \ - undefined('there is no parent block called %r.' % - self.name, name='super') - return BlockReference(self.name, self._context, self._stack, - self._depth + 1) + return self._context.environment.undefined( + "there is no parent block called %r." % self.name, name="super" + ) + return BlockReference(self.name, self._context, self._stack, self._depth + 1) @internalcode def __call__(self): @@ -538,8 +562,7 @@ class LoopContext: """ if self._recurse is None: raise TypeError( - "The loop must have the 'recursive' marker to be" - " called recursively." + "The loop must have the 'recursive' marker to be called recursively." ) return self._recurse(iterable, self._recurse, depth=self.depth) @@ -551,9 +574,17 @@ class LoopContext: class Macro(object): """Wraps a macro function.""" - def __init__(self, environment, func, name, arguments, - catch_kwargs, catch_varargs, caller, - default_autoescape=None): + def __init__( + self, + environment, + func, + name, + arguments, + catch_kwargs, + catch_varargs, + caller, + default_autoescape=None, + ): self._environment = environment self._func = func self._argument_count = len(arguments) @@ -562,7 +593,7 @@ class Macro(object): self.catch_kwargs = catch_kwargs self.catch_varargs = catch_varargs self.caller = caller - self.explicit_caller = 'caller' in arguments + self.explicit_caller = "caller" in arguments if default_autoescape is None: default_autoescape = environment.autoescape self._default_autoescape = default_autoescape @@ -593,7 +624,7 @@ class Macro(object): autoescape = self._default_autoescape # try to consume the positional arguments - arguments = list(args[:self._argument_count]) + arguments = list(args[: self._argument_count]) off = len(arguments) # For information why this is necessary refer to the handling @@ -604,12 +635,12 @@ class Macro(object): # arguments expected we start filling in keyword arguments # and defaults. if off != self._argument_count: - for idx, name in enumerate(self.arguments[len(arguments):]): + for idx, name in enumerate(self.arguments[len(arguments) :]): try: value = kwargs.pop(name) except KeyError: value = missing - if name == 'caller': + if name == "caller": found_caller = True arguments.append(value) else: @@ -619,26 +650,31 @@ class Macro(object): # if not also changed in the compiler's `function_scoping` method. # the order is caller, keyword arguments, positional arguments! if self.caller and not found_caller: - caller = kwargs.pop('caller', None) + caller = kwargs.pop("caller", None) if caller is None: - caller = self._environment.undefined('No caller defined', - name='caller') + caller = self._environment.undefined("No caller defined", name="caller") arguments.append(caller) if self.catch_kwargs: arguments.append(kwargs) elif kwargs: - if 'caller' in kwargs: - raise TypeError('macro %r was invoked with two values for ' - 'the special caller argument. This is ' - 'most likely a bug.' % self.name) - raise TypeError('macro %r takes no keyword argument %r' % - (self.name, next(iter(kwargs)))) + if "caller" in kwargs: + raise TypeError( + "macro %r was invoked with two values for " + "the special caller argument. This is " + "most likely a bug." % self.name + ) + raise TypeError( + "macro %r takes no keyword argument %r" + % (self.name, next(iter(kwargs))) + ) if self.catch_varargs: - arguments.append(args[self._argument_count:]) + arguments.append(args[self._argument_count :]) elif len(args) > self._argument_count: - raise TypeError('macro %r takes not more than %d argument(s)' % - (self.name, len(self.arguments))) + raise TypeError( + "macro %r takes not more than %d argument(s)" + % (self.name, len(self.arguments)) + ) return self._invoke(arguments, autoescape) @@ -650,9 +686,9 @@ class Macro(object): return rv def __repr__(self): - return '<%s %s>' % ( + return "<%s %s>" % ( self.__class__.__name__, - self.name is None and 'anonymous' or repr(self.name) + self.name is None and "anonymous" or repr(self.name), ) @@ -671,8 +707,13 @@ class Undefined(object): ... jinja2.exceptions.UndefinedError: 'foo' is undefined """ - __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name', - '_undefined_exception') + + __slots__ = ( + "_undefined_hint", + "_undefined_obj", + "_undefined_name", + "_undefined_exception", + ) def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): self._undefined_hint = hint @@ -689,17 +730,17 @@ class Undefined(object): return self._undefined_hint if self._undefined_obj is missing: - return '%r is undefined' % self._undefined_name + return "%r is undefined" % self._undefined_name if not isinstance(self._undefined_name, string_types): - return '%s has no element %r' % ( + return "%s has no element %r" % ( object_type_repr(self._undefined_obj), - self._undefined_name + self._undefined_name, ) - return '%r has no attribute %r' % ( + return "%r has no attribute %r" % ( object_type_repr(self._undefined_obj), - self._undefined_name + self._undefined_name, ) @internalcode @@ -711,16 +752,55 @@ class Undefined(object): @internalcode def __getattr__(self, name): - if name[:2] == '__': + 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__ = \ - __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \ - __float__ = __complex__ = __pow__ = __rpow__ = __sub__ = \ - __rsub__ = _fail_with_undefined_error + __add__ = ( + __radd__ + ) = ( + __mul__ + ) = ( + __rmul__ + ) = ( + __div__ + ) = ( + __rdiv__ + ) = ( + __truediv__ + ) = ( + __rtruediv__ + ) = ( + __floordiv__ + ) = ( + __rfloordiv__ + ) = ( + __mod__ + ) = ( + __rmod__ + ) = ( + __pos__ + ) = ( + __neg__ + ) = ( + __call__ + ) = ( + __getitem__ + ) = ( + __lt__ + ) = ( + __le__ + ) = ( + __gt__ + ) = ( + __ge__ + ) = ( + __int__ + ) = ( + __float__ + ) = ( + __complex__ + ) = __pow__ = __rpow__ = __sub__ = __rsub__ = _fail_with_undefined_error def __eq__(self, other): return type(self) is type(other) @@ -732,7 +812,7 @@ class Undefined(object): return id(type(self)) def __str__(self): - return u'' + return u"" def __len__(self): return 0 @@ -743,10 +823,11 @@ class Undefined(object): def __nonzero__(self): return False + __bool__ = __nonzero__ def __repr__(self): - return 'Undefined' + return "Undefined" def make_logging_undefined(logger=None, base=None): @@ -771,6 +852,7 @@ def make_logging_undefined(logger=None, base=None): """ if logger is None: import logging + logger = logging.getLogger(__name__) logger.addHandler(logging.StreamHandler(sys.stderr)) if base is None: @@ -779,26 +861,27 @@ def make_logging_undefined(logger=None, base=None): def _log_message(undef): if undef._undefined_hint is None: if undef._undefined_obj is missing: - hint = '%s is undefined' % undef._undefined_name + hint = "%s is undefined" % undef._undefined_name elif not isinstance(undef._undefined_name, string_types): - hint = '%s has no element %s' % ( + hint = "%s has no element %s" % ( object_type_repr(undef._undefined_obj), - undef._undefined_name) + undef._undefined_name, + ) else: - hint = '%s has no attribute %s' % ( + hint = "%s has no attribute %s" % ( object_type_repr(undef._undefined_obj), - undef._undefined_name) + undef._undefined_name, + ) else: hint = undef._undefined_hint - logger.warning('Template variable warning: %s', hint) + logger.warning("Template variable warning: %s", hint) class LoggingUndefined(base): - def _fail_with_undefined_error(self, *args, **kwargs): try: return base._fail_with_undefined_error(self, *args, **kwargs) except self._undefined_exception as e: - logger.error('Template variable error: %s', str(e)) + logger.error("Template variable error: %s", str(e)) raise e def __str__(self): @@ -812,6 +895,7 @@ def make_logging_undefined(logger=None, base=None): return rv if PY2: + def __nonzero__(self): rv = base.__nonzero__(self) _log_message(self) @@ -821,7 +905,9 @@ def make_logging_undefined(logger=None, base=None): rv = base.__unicode__(self) _log_message(self) return rv + else: + def __bool__(self): rv = base.__bool__(self) _log_message(self) @@ -848,6 +934,7 @@ class ChainableUndefined(Undefined): .. versionadded:: 2.11.0 """ + __slots__ = () def __html__(self): @@ -873,17 +960,18 @@ class DebugUndefined(Undefined): ... jinja2.exceptions.UndefinedError: 'foo' is undefined """ + __slots__ = () def __str__(self): if self._undefined_hint is None: if self._undefined_obj is missing: - return u'{{ %s }}' % self._undefined_name - return '{{ no such element: %s[%r] }}' % ( + return u"{{ %s }}" % self._undefined_name + return "{{ no such element: %s[%r] }}" % ( object_type_repr(self._undefined_obj), - self._undefined_name + self._undefined_name, ) - return u'{{ undefined value printed: %s }}' % self._undefined_hint + return u"{{ undefined value printed: %s }}" % self._undefined_hint @implements_to_string @@ -906,13 +994,22 @@ class StrictUndefined(Undefined): ... jinja2.exceptions.UndefinedError: 'foo' is undefined """ + __slots__ = () - __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \ - __ne__ = __bool__ = __hash__ = \ - Undefined._fail_with_undefined_error + __iter__ = ( + __str__ + ) = ( + __len__ + ) = ( + __nonzero__ + ) = __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error # remove remaining slots attributes, after the metaclass did the magic they # are unneeded and irritating as they contain wrong data for the subclasses. -del Undefined.__slots__, ChainableUndefined.__slots__, \ - DebugUndefined.__slots__, StrictUndefined.__slots__ +del ( + Undefined.__slots__, + ChainableUndefined.__slots__, + DebugUndefined.__slots__, + StrictUndefined.__slots__, +) |