diff options
author | floatdrop <floatdrop@yandex-team.ru> | 2022-02-10 16:47:15 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:47:15 +0300 |
commit | e63b84f1d39557d9e46ac380b1f388271894293c (patch) | |
tree | 338cdaff3fb027e030b847db66df06019a0e3149 /contrib/python/Jinja2/py2/jinja2/runtime.py | |
parent | f60febb7ea449535e7b073c386c7ff0539637fc0 (diff) | |
download | ydb-e63b84f1d39557d9e46ac380b1f388271894293c.tar.gz |
Restoring authorship annotation for <floatdrop@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/Jinja2/py2/jinja2/runtime.py')
-rw-r--r-- | contrib/python/Jinja2/py2/jinja2/runtime.py | 1142 |
1 files changed, 571 insertions, 571 deletions
diff --git a/contrib/python/Jinja2/py2/jinja2/runtime.py b/contrib/python/Jinja2/py2/jinja2/runtime.py index 3ad7968624..850f82da1c 100644 --- a/contrib/python/Jinja2/py2/jinja2/runtime.py +++ b/contrib/python/Jinja2/py2/jinja2/runtime.py @@ -1,13 +1,13 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- """The runtime functions and state used by compiled templates.""" -import sys -from itertools import chain -from types import MethodType - +import sys +from itertools import chain +from types import MethodType + from markupsafe import escape # noqa: F401 from markupsafe import Markup from markupsafe import soft_unicode - + from ._compat import abc from ._compat import imap from ._compat import implements_iterator @@ -27,8 +27,8 @@ from .utils import internalcode from .utils import missing from .utils import Namespace # noqa: F401 from .utils import object_type_repr - -# these variables are exported to the template runtime + +# these variables are exported to the template runtime exported = [ "LoopContext", "TemplateReference", @@ -46,35 +46,35 @@ exported = [ "Namespace", "Undefined", ] - -#: the name of the function that is used to convert something into -#: a string. We can just use the text type here. -to_string = text_type - - + +#: the name of the function that is used to convert something into +#: a string. We can just use the text type here. +to_string = text_type + + def identity(x): """Returns its argument. Useful for certain things in the environment. """ return x - - -def markup_join(seq): - """Concatenation that escapes if necessary and converts to unicode.""" - buf = [] - iterator = imap(soft_unicode, seq) - for arg in iterator: - buf.append(arg) + + +def markup_join(seq): + """Concatenation that escapes if necessary and converts to unicode.""" + buf = [] + iterator = imap(soft_unicode, seq) + for arg in iterator: + buf.append(arg) if hasattr(arg, "__html__"): return Markup(u"").join(chain(buf, iterator)) - return concat(buf) - - -def unicode_join(seq): - """Simple args to unicode conversion and concatenation.""" - return concat(imap(text_type, seq)) - - + return concat(buf) + + +def unicode_join(seq): + """Simple args to unicode conversion and concatenation.""" + return concat(imap(text_type, seq)) + + def new_context( environment, template_name, @@ -85,311 +85,311 @@ def new_context( locals=None, ): """Internal helper for context creation.""" - if vars is None: - vars = {} - if shared: - parent = vars - else: - parent = dict(globals or (), **vars) - if locals: - # if the parent is shared a copy should be created because - # we don't want to modify the dict passed - if shared: - parent = dict(parent) - for key, value in iteritems(locals): - if value is not missing: - parent[key] = value + if vars is None: + vars = {} + if shared: + parent = vars + else: + parent = dict(globals or (), **vars) + if locals: + # if the parent is shared a copy should be created because + # we don't want to modify the dict passed + if shared: + parent = dict(parent) + for key, value in iteritems(locals): + if value is not missing: + parent[key] = value return environment.context_class(environment, parent, template_name, blocks) - - -class TemplateReference(object): - """The `self` in templates.""" - - def __init__(self, context): - self.__context = context - - def __getitem__(self, name): - blocks = self.__context.blocks[name] - return BlockReference(name, self.__context, blocks, 0) - - def __repr__(self): + + +class TemplateReference(object): + """The `self` in templates.""" + + def __init__(self, context): + self.__context = context + + def __getitem__(self, name): + blocks = self.__context.blocks[name] + return BlockReference(name, self.__context, blocks, 0) + + def __repr__(self): return "<%s %r>" % (self.__class__.__name__, self.__context.name) - - -def _get_func(x): + + +def _get_func(x): return getattr(x, "__func__", x) - - -class ContextMeta(type): + + +class ContextMeta(type): def __new__(mcs, name, bases, d): rv = type.__new__(mcs, name, bases, d) - if bases == (): - return rv - - resolve = _get_func(rv.resolve) - default_resolve = _get_func(Context.resolve) - resolve_or_missing = _get_func(rv.resolve_or_missing) - default_resolve_or_missing = _get_func(Context.resolve_or_missing) - - # If we have a changed resolve but no changed default or missing - # resolve we invert the call logic. + if bases == (): + return rv + + resolve = _get_func(rv.resolve) + default_resolve = _get_func(Context.resolve) + resolve_or_missing = _get_func(rv.resolve_or_missing) + default_resolve_or_missing = _get_func(Context.resolve_or_missing) + + # 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 ): - rv._legacy_resolve_mode = True + rv._legacy_resolve_mode = True elif ( resolve is default_resolve and resolve_or_missing is default_resolve_or_missing ): - rv._fast_resolve_mode = True - - return rv - - -def resolve_or_missing(context, key, missing=missing): - if key in context.vars: - return context.vars[key] - if key in context.parent: - return context.parent[key] - return missing - - -class Context(with_metaclass(ContextMeta)): - """The template context holds the variables of a template. It stores the - values passed to the template and also the names the template exports. - Creating instances is neither supported nor useful as it's created - automatically at various stages of the template evaluation and should not - be created by hand. - - The context is immutable. Modifications on :attr:`parent` **must not** - happen and modifications on :attr:`vars` are allowed from generated - template code only. Template filters and global functions marked as - :func:`contextfunction`\\s get the active context passed as first argument - and are allowed to access the context read-only. - - The template context supports read only dict operations (`get`, - `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`, - `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve` - 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 - _fast_resolve_mode = False - - 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 - - # create the initial mapping of blocks. Whenever template inheritance - # takes place the runtime will update this mapping with the new blocks - # from the template. - self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) - - # In case we detect the fast resolve mode we can set up an alias - # here that bypasses the legacy code logic. - if self._fast_resolve_mode: - self.resolve_or_missing = MethodType(resolve_or_missing, self) - - def super(self, name, current): - """Render a parent block.""" - try: - blocks = self.blocks[name] - index = blocks.index(current) + 1 - blocks[index] - except LookupError: + rv._fast_resolve_mode = True + + return rv + + +def resolve_or_missing(context, key, missing=missing): + if key in context.vars: + return context.vars[key] + if key in context.parent: + return context.parent[key] + return missing + + +class Context(with_metaclass(ContextMeta)): + """The template context holds the variables of a template. It stores the + values passed to the template and also the names the template exports. + Creating instances is neither supported nor useful as it's created + automatically at various stages of the template evaluation and should not + be created by hand. + + The context is immutable. Modifications on :attr:`parent` **must not** + happen and modifications on :attr:`vars` are allowed from generated + template code only. Template filters and global functions marked as + :func:`contextfunction`\\s get the active context passed as first argument + and are allowed to access the context read-only. + + The template context supports read only dict operations (`get`, + `keys`, `values`, `items`, `iterkeys`, `itervalues`, `iteritems`, + `__getitem__`, `__contains__`). Additionally there is a :meth:`resolve` + 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 + _fast_resolve_mode = False + + 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 + + # create the initial mapping of blocks. Whenever template inheritance + # takes place the runtime will update this mapping with the new blocks + # from the template. + self.blocks = dict((k, [v]) for k, v in iteritems(blocks)) + + # In case we detect the fast resolve mode we can set up an alias + # here that bypasses the legacy code logic. + if self._fast_resolve_mode: + self.resolve_or_missing = MethodType(resolve_or_missing, self) + + def super(self, name, current): + """Render a parent block.""" + try: + blocks = self.blocks[name] + index = blocks.index(current) + 1 + blocks[index] + except LookupError: 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): - """Returns an item from the template context, if it doesn't exist - `default` is returned. - """ - try: - return self[key] - except KeyError: - return default - - def resolve(self, key): - """Looks up a variable like `__getitem__` or `get` but returns an - :class:`Undefined` object with the name of the name looked up. - """ - if self._legacy_resolve_mode: - rv = resolve_or_missing(self, key) - else: - rv = self.resolve_or_missing(key) - if rv is missing: - return self.environment.undefined(name=key) - return rv - - def resolve_or_missing(self, key): - """Resolves a variable like :meth:`resolve` but returns the - special `missing` value if it cannot be found. - """ - if self._legacy_resolve_mode: - rv = self.resolve(key) - if isinstance(rv, Undefined): - rv = missing - return rv - return resolve_or_missing(self, key) - - def get_exported(self): - """Get a new dict with the exported variables.""" - return dict((k, self.vars[k]) for k in self.exported_vars) - - def get_all(self): - """Return the complete context as dict including the exported - variables. For optimizations reasons this might not return an - actual copy so be careful with using it. - """ - if not self.vars: - return self.parent - if not self.parent: - return self.vars - return dict(self.parent, **self.vars) - - @internalcode + return BlockReference(name, self, blocks, index) + + def get(self, key, default=None): + """Returns an item from the template context, if it doesn't exist + `default` is returned. + """ + try: + return self[key] + except KeyError: + return default + + def resolve(self, key): + """Looks up a variable like `__getitem__` or `get` but returns an + :class:`Undefined` object with the name of the name looked up. + """ + if self._legacy_resolve_mode: + rv = resolve_or_missing(self, key) + else: + rv = self.resolve_or_missing(key) + if rv is missing: + return self.environment.undefined(name=key) + return rv + + def resolve_or_missing(self, key): + """Resolves a variable like :meth:`resolve` but returns the + special `missing` value if it cannot be found. + """ + if self._legacy_resolve_mode: + rv = self.resolve(key) + if isinstance(rv, Undefined): + rv = missing + return rv + return resolve_or_missing(self, key) + + def get_exported(self): + """Get a new dict with the exported variables.""" + return dict((k, self.vars[k]) for k in self.exported_vars) + + def get_all(self): + """Return the complete context as dict including the exported + variables. For optimizations reasons this might not return an + actual copy so be careful with using it. + """ + if not self.vars: + return self.parent + if not self.parent: + return self.vars + return dict(self.parent, **self.vars) + + @internalcode def call(__self, __obj, *args, **kwargs): # noqa: B902 - """Call the callable with the arguments and keyword arguments - provided but inject the active context or environment as first - argument if the callable is a :func:`contextfunction` or - :func:`environmentfunction`. - """ - if __debug__: - __traceback_hide__ = True # noqa - - # Allow callable classes to take a context + """Call the callable with the arguments and keyword arguments + provided but inject the active context or environment as first + argument if the callable is a :func:`contextfunction` or + :func:`environmentfunction`. + """ + if __debug__: + __traceback_hide__ = True # noqa + + # Allow callable classes to take a context if hasattr(__obj, "__call__"): # noqa: B004 - fn = __obj.__call__ + fn = __obj.__call__ for fn_type in ( "contextfunction", "evalcontextfunction", "environmentfunction", ): - if hasattr(fn, fn_type): - __obj = fn - break - + if hasattr(fn, fn_type): + __obj = fn + break + if callable(__obj): if getattr(__obj, "contextfunction", False) is True: - args = (__self,) + args + args = (__self,) + args elif getattr(__obj, "evalcontextfunction", False) is True: - args = (__self.eval_ctx,) + args + args = (__self.eval_ctx,) + args elif getattr(__obj, "environmentfunction", False) is True: - args = (__self.environment,) + args - try: - return __obj(*args, **kwargs) - except StopIteration: + 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" ) - - 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. - """ + + 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.eval_ctx = self.eval_ctx - context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) - return context - + context.eval_ctx = self.eval_ctx + context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks)) + return context + def _all(meth): # noqa: B902 def proxy(self): return getattr(self.get_all(), meth)() - proxy.__doc__ = getattr(dict, meth).__doc__ - proxy.__name__ = meth - return proxy - + proxy.__doc__ = getattr(dict, meth).__doc__ + proxy.__name__ = meth + return proxy + keys = _all("keys") values = _all("values") items = _all("items") - - # not available on python 3 - if PY2: + + # not available on python 3 + if PY2: iterkeys = _all("iterkeys") itervalues = _all("itervalues") iteritems = _all("iteritems") - del _all - - def __contains__(self, name): - return name in self.vars or name in self.parent - - def __getitem__(self, key): - """Lookup a variable or raise `KeyError` if the variable is - undefined. - """ - item = self.resolve_or_missing(key) - if item is missing: - raise KeyError(key) - return item - - def __repr__(self): + del _all + + def __contains__(self, name): + return name in self.vars or name in self.parent + + def __getitem__(self, key): + """Lookup a variable or raise `KeyError` if the variable is + undefined. + """ + item = self.resolve_or_missing(key) + if item is missing: + raise KeyError(key) + return item + + def __repr__(self): return "<%s %s of %r>" % ( - self.__class__.__name__, - repr(self.get_all()), + self.__class__.__name__, + repr(self.get_all()), self.name, - ) - - + ) + + abc.Mapping.register(Context) - - -class BlockReference(object): - """One block on a template reference.""" - - def __init__(self, name, context, stack, depth): - self.name = name - self._context = context - self._stack = stack - self._depth = depth - - @property - def super(self): - """Super the block.""" - if self._depth + 1 >= len(self._stack): + + +class BlockReference(object): + """One block on a template reference.""" + + def __init__(self, name, context, stack, depth): + self.name = name + self._context = context + self._stack = stack + self._depth = depth + + @property + 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) - - @internalcode - def __call__(self): - rv = concat(self._stack[self._depth](self._context)) - if self._context.eval_ctx.autoescape: - rv = Markup(rv) - return rv - - + + @internalcode + def __call__(self): + rv = concat(self._stack[self._depth](self._context)) + if self._context.eval_ctx.autoescape: + rv = Markup(rv) + return rv + + @implements_iterator class LoopContext: """A wrapper iterable for dynamic ``for`` loops, with information about the loop and iteration. """ - + #: Current iteration of the loop, starting at 0. index0 = -1 - _length = None + _length = None _after = missing _current = missing _before = missing _last_changed_value = missing - + def __init__(self, iterable, undefined, recurse=None, depth0=0): """ :param iterable: Iterable to wrap. @@ -401,68 +401,68 @@ class LoopContext: """ self._iterable = iterable self._iterator = self._to_iterator(iterable) - self._undefined = undefined - self._recurse = recurse + self._undefined = undefined + self._recurse = recurse #: How many levels deep a recursive loop currently is, starting at 0. - self.depth0 = depth0 - + self.depth0 = depth0 + @staticmethod def _to_iterator(iterable): return iter(iterable) - + @property def length(self): """Length of the iterable. - + If the iterable is a generator or otherwise does not have a size, it is eagerly evaluated to get a size. """ if self._length is not None: return self._length - + try: self._length = len(self._iterable) except TypeError: iterable = list(self._iterator) self._iterator = self._to_iterator(iterable) self._length = len(iterable) + self.index + (self._after is not missing) - + return self._length - - def __len__(self): - return self.length - + + def __len__(self): + return self.length + @property def depth(self): """How many levels deep a recursive loop currently is, starting at 1.""" return self.depth0 + 1 - + @property def index(self): """Current iteration of the loop, starting at 1.""" return self.index0 + 1 - + @property def revindex0(self): """Number of iterations from the end of the loop, ending at 0. - + Requires calculating :attr:`length`. """ return self.length - self.index - + @property def revindex(self): """Number of iterations from the end of the loop, ending at 1. - + Requires calculating :attr:`length`. """ return self.length - self.index0 - + @property def first(self): """Whether this is the first iteration of the loop.""" return self.index0 == 0 - + def _peek_next(self): """Return the next element in the iterable, or :data:`missing` if the iterable is exhausted. Only peeks one item ahead, caching @@ -475,16 +475,16 @@ class LoopContext: self._after = next(self._iterator, missing) return self._after - @property + @property def last(self): """Whether this is the last iteration of the loop. - + Causes the iterable to advance early. See :func:`itertools.groupby` for issues this can cause. The :func:`groupby` filter avoids that issue. """ return self._peek_next() is missing - + @property def previtem(self): """The item in the previous iteration. Undefined during the @@ -492,20 +492,20 @@ class LoopContext: """ if self.first: return self._undefined("there is no previous item") - + return self._before - + @property def nextitem(self): """The item in the next iteration. Undefined during the last iteration. - + Causes the iterable to advance early. See :func:`itertools.groupby` for issues this can cause. The :func:`groupby` filter avoids that issue. """ rv = self._peek_next() - + if rv is missing: return self._undefined("there is no next item") @@ -534,21 +534,21 @@ class LoopContext: return False - def __iter__(self): - return self - - def __next__(self): + def __iter__(self): + return self + + def __next__(self): if self._after is not missing: rv = self._after self._after = missing else: rv = next(self._iterator) - + self.index0 += 1 self._before = self._current self._current = rv return rv, self - + @internalcode def __call__(self, iterable): """When iterating over nested data, render the body of the loop @@ -567,9 +567,9 @@ class LoopContext: return "<%s %d/%d>" % (self.__class__.__name__, self.index, self.length) -class Macro(object): - """Wraps a macro function.""" - +class Macro(object): + """Wraps a macro function.""" + def __init__( self, environment, @@ -581,79 +581,79 @@ class Macro(object): caller, default_autoescape=None, ): - self._environment = environment - self._func = func - self._argument_count = len(arguments) - self.name = name - self.arguments = arguments - self.catch_kwargs = catch_kwargs - self.catch_varargs = catch_varargs - self.caller = caller + self._environment = environment + self._func = func + self._argument_count = len(arguments) + self.name = name + self.arguments = arguments + self.catch_kwargs = catch_kwargs + self.catch_varargs = catch_varargs + self.caller = caller self.explicit_caller = "caller" in arguments - if default_autoescape is None: - default_autoescape = environment.autoescape - self._default_autoescape = default_autoescape - - @internalcode - @evalcontextfunction - def __call__(self, *args, **kwargs): - # This requires a bit of explanation, In the past we used to - # decide largely based on compile-time information if a macro is - # safe or unsafe. While there was a volatile mode it was largely - # unused for deciding on escaping. This turns out to be + if default_autoescape is None: + default_autoescape = environment.autoescape + self._default_autoescape = default_autoescape + + @internalcode + @evalcontextfunction + def __call__(self, *args, **kwargs): + # This requires a bit of explanation, In the past we used to + # decide largely based on compile-time information if a macro is + # safe or unsafe. While there was a volatile mode it was largely + # unused for deciding on escaping. This turns out to be # problematic for macros because whether a macro is safe depends not # on the escape mode when it was defined, but rather when it was used. - # - # Because however we export macros from the module system and - # there are historic callers that do not pass an eval context (and - # will continue to not pass one), we need to perform an instance - # check here. - # - # This is considered safe because an eval context is not a valid + # + # Because however we export macros from the module system and + # there are historic callers that do not pass an eval context (and + # will continue to not pass one), we need to perform an instance + # check here. + # + # This is considered safe because an eval context is not a valid # argument to callables otherwise anyway. Worst case here is - # that if no eval context is passed we fall back to the compile - # time autoescape flag. - if args and isinstance(args[0], EvalContext): - autoescape = args[0].autoescape - args = args[1:] - else: - autoescape = self._default_autoescape - - # try to consume the positional arguments + # that if no eval context is passed we fall back to the compile + # time autoescape flag. + if args and isinstance(args[0], EvalContext): + autoescape = args[0].autoescape + args = args[1:] + else: + autoescape = self._default_autoescape + + # try to consume the positional arguments arguments = list(args[: self._argument_count]) - off = len(arguments) - - # For information why this is necessary refer to the handling - # of caller in the `macro_body` handler in the compiler. - found_caller = False - - # 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: + off = len(arguments) + + # For information why this is necessary refer to the handling + # of caller in the `macro_body` handler in the compiler. + found_caller = False + + # 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 name in self.arguments[len(arguments) :]: - try: - value = kwargs.pop(name) - except KeyError: - value = missing + try: + value = kwargs.pop(name) + except KeyError: + value = missing if name == "caller": - found_caller = True - arguments.append(value) - else: - found_caller = self.explicit_caller - - # it's important that the order of these arguments does not change - # 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: + found_caller = True + arguments.append(value) + else: + found_caller = self.explicit_caller + + # it's important that the order of these arguments does not change + # 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) - if caller is None: + if caller is None: caller = self._environment.undefined("No caller defined", name="caller") - arguments.append(caller) - - if self.catch_kwargs: - arguments.append(kwargs) - elif kwargs: + 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 " @@ -664,46 +664,46 @@ class Macro(object): "macro %r takes no keyword argument %r" % (self.name, next(iter(kwargs))) ) - if self.catch_varargs: + if self.catch_varargs: arguments.append(args[self._argument_count :]) - elif len(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)) ) - - return self._invoke(arguments, autoescape) - - def _invoke(self, arguments, autoescape): - """This method is being swapped out by the async implementation.""" - rv = self._func(*arguments) - if autoescape: - rv = Markup(rv) - return rv - - def __repr__(self): + + return self._invoke(arguments, autoescape) + + def _invoke(self, arguments, autoescape): + """This method is being swapped out by the async implementation.""" + rv = self._func(*arguments) + if autoescape: + rv = Markup(rv) + return rv + + def __repr__(self): return "<%s %s>" % ( - self.__class__.__name__, + self.__class__.__name__, self.name is None and "anonymous" or repr(self.name), - ) - - -@implements_to_string -class Undefined(object): - """The default undefined type. This undefined type can be printed and + ) + + +@implements_to_string +class Undefined(object): + """The default undefined type. This undefined type can be printed and iterated over, but every other access will raise an :exc:`UndefinedError`: - - >>> foo = Undefined(name='foo') - >>> str(foo) - '' - >>> not foo - True - >>> foo + 42 - Traceback (most recent call last): - ... - jinja2.exceptions.UndefinedError: 'foo' is undefined - """ - + + >>> foo = Undefined(name='foo') + >>> str(foo) + '' + >>> not foo + True + >>> foo + 42 + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + """ + __slots__ = ( "_undefined_hint", "_undefined_obj", @@ -711,12 +711,12 @@ class Undefined(object): "_undefined_exception", ) - def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): - self._undefined_hint = hint - self._undefined_obj = obj - self._undefined_name = name - self._undefined_exception = exc - + def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError): + self._undefined_hint = hint + self._undefined_obj = obj + self._undefined_name = name + self._undefined_exception = exc + @property def _undefined_message(self): """Build a message about the undefined value based on how it was @@ -739,19 +739,19 @@ class Undefined(object): self._undefined_name, ) - @internalcode - def _fail_with_undefined_error(self, *args, **kwargs): + @internalcode + def _fail_with_undefined_error(self, *args, **kwargs): """Raise an :exc:`UndefinedError` when operations are performed on the undefined value. - """ + """ raise self._undefined_exception(self._undefined_message) - - @internalcode - def __getattr__(self, name): + + @internalcode + def __getattr__(self, name): if name[:2] == "__": - raise AttributeError(name) - return self._fail_with_undefined_error() - + raise AttributeError(name) + return self._fail_with_undefined_error() + __add__ = ( __radd__ ) = ( @@ -797,121 +797,121 @@ class Undefined(object): ) = ( __complex__ ) = __pow__ = __rpow__ = __sub__ = __rsub__ = _fail_with_undefined_error - - def __eq__(self, other): - return type(self) is type(other) - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return id(type(self)) - - def __str__(self): + + def __eq__(self, other): + return type(self) is type(other) + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return id(type(self)) + + def __str__(self): return u"" - - def __len__(self): - return 0 - - def __iter__(self): - if 0: - yield None - - def __nonzero__(self): - return False - - __bool__ = __nonzero__ - - def __repr__(self): + + def __len__(self): + return 0 + + def __iter__(self): + if 0: + yield None + + def __nonzero__(self): + return False + + __bool__ = __nonzero__ + + def __repr__(self): return "Undefined" - - -def make_logging_undefined(logger=None, base=None): - """Given a logger object this returns a new undefined class that will - log certain failures. It will log iterations and printing. If no - logger is given a default logger is created. - - Example:: - - logger = logging.getLogger(__name__) - LoggingUndefined = make_logging_undefined( - logger=logger, - base=Undefined - ) - - .. versionadded:: 2.8 - - :param logger: the logger to use. If not provided, a default logger - is created. - :param base: the base class to add logging functionality to. This - defaults to :class:`Undefined`. - """ - if logger is None: - import logging - - logger = logging.getLogger(__name__) - logger.addHandler(logging.StreamHandler(sys.stderr)) - if base is None: - base = Undefined - - def _log_message(undef): - if undef._undefined_hint is None: - if undef._undefined_obj is missing: + + +def make_logging_undefined(logger=None, base=None): + """Given a logger object this returns a new undefined class that will + log certain failures. It will log iterations and printing. If no + logger is given a default logger is created. + + Example:: + + logger = logging.getLogger(__name__) + LoggingUndefined = make_logging_undefined( + logger=logger, + base=Undefined + ) + + .. versionadded:: 2.8 + + :param logger: the logger to use. If not provided, a default logger + is created. + :param base: the base class to add logging functionality to. This + defaults to :class:`Undefined`. + """ + if logger is None: + import logging + + logger = logging.getLogger(__name__) + logger.addHandler(logging.StreamHandler(sys.stderr)) + if base is None: + base = Undefined + + def _log_message(undef): + if undef._undefined_hint is None: + if undef._undefined_obj is missing: hint = "%s is undefined" % undef._undefined_name - elif not isinstance(undef._undefined_name, string_types): + elif not isinstance(undef._undefined_name, string_types): hint = "%s has no element %s" % ( - object_type_repr(undef._undefined_obj), + object_type_repr(undef._undefined_obj), undef._undefined_name, ) - else: + else: hint = "%s has no attribute %s" % ( - object_type_repr(undef._undefined_obj), + object_type_repr(undef._undefined_obj), undef._undefined_name, ) - else: - hint = undef._undefined_hint + else: + hint = undef._undefined_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: + + 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)) - raise e - - def __str__(self): - rv = base.__str__(self) - _log_message(self) - return rv - - def __iter__(self): - rv = base.__iter__(self) - _log_message(self) - return rv - - if PY2: - - def __nonzero__(self): - rv = base.__nonzero__(self) - _log_message(self) - return rv - - def __unicode__(self): - rv = base.__unicode__(self) - _log_message(self) - return rv - - else: - - def __bool__(self): - rv = base.__bool__(self) - _log_message(self) - return rv - - return LoggingUndefined - - + raise e + + def __str__(self): + rv = base.__str__(self) + _log_message(self) + return rv + + def __iter__(self): + rv = base.__iter__(self) + _log_message(self) + return rv + + if PY2: + + def __nonzero__(self): + rv = base.__nonzero__(self) + _log_message(self) + return rv + + def __unicode__(self): + rv = base.__unicode__(self) + _log_message(self) + return rv + + else: + + def __bool__(self): + rv = base.__bool__(self) + _log_message(self) + return rv + + return LoggingUndefined + + # No @implements_to_string decorator here because __str__ # is not overwritten from Undefined in this class. # This would cause a recursion error in Python 2. @@ -942,56 +942,56 @@ class ChainableUndefined(Undefined): __getitem__ = __getattr__ -@implements_to_string -class DebugUndefined(Undefined): - """An undefined that returns the debug info when printed. - - >>> foo = DebugUndefined(name='foo') - >>> str(foo) - '{{ foo }}' - >>> not foo - True - >>> foo + 42 - Traceback (most recent call last): - ... - jinja2.exceptions.UndefinedError: 'foo' is undefined - """ - - __slots__ = () - - def __str__(self): - if self._undefined_hint is None: - if self._undefined_obj is missing: +@implements_to_string +class DebugUndefined(Undefined): + """An undefined that returns the debug info when printed. + + >>> foo = DebugUndefined(name='foo') + >>> str(foo) + '{{ foo }}' + >>> not foo + True + >>> foo + 42 + Traceback (most recent call last): + ... + 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] }}" % ( - object_type_repr(self._undefined_obj), + object_type_repr(self._undefined_obj), self._undefined_name, - ) + ) return u"{{ undefined value printed: %s }}" % self._undefined_hint - - -@implements_to_string -class StrictUndefined(Undefined): - """An undefined that barks on print and iteration as well as boolean - tests and all kinds of comparisons. In other words: you can do nothing - with it except checking if it's defined using the `defined` test. - - >>> foo = StrictUndefined(name='foo') - >>> str(foo) - Traceback (most recent call last): - ... - jinja2.exceptions.UndefinedError: 'foo' is undefined - >>> not foo - Traceback (most recent call last): - ... - jinja2.exceptions.UndefinedError: 'foo' is undefined - >>> foo + 42 - Traceback (most recent call last): - ... - jinja2.exceptions.UndefinedError: 'foo' is undefined - """ - - __slots__ = () + + +@implements_to_string +class StrictUndefined(Undefined): + """An undefined that barks on print and iteration as well as boolean + tests and all kinds of comparisons. In other words: you can do nothing + with it except checking if it's defined using the `defined` test. + + >>> foo = StrictUndefined(name='foo') + >>> str(foo) + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + >>> not foo + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + >>> foo + 42 + Traceback (most recent call last): + ... + jinja2.exceptions.UndefinedError: 'foo' is undefined + """ + + __slots__ = () __iter__ = ( __str__ ) = ( @@ -999,10 +999,10 @@ class StrictUndefined(Undefined): ) = ( __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. + + +# 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__, |