测试gitnore

This commit is contained in:
ladeng07
2022-05-06 15:45:57 +08:00
parent 12f390949b
commit 51552904f9
2347 changed files with 120102 additions and 53549 deletions
+166 -237
View File
@@ -59,36 +59,41 @@ from django.template.context import BaseContext
from django.utils.formats import localize
from django.utils.html import conditional_escape, escape
from django.utils.regex_helper import _lazy_re_compile
from django.utils.safestring import SafeData, SafeString, mark_safe
from django.utils.text import get_text_list, smart_split, unescape_string_literal
from django.utils.safestring import SafeData, mark_safe
from django.utils.text import (
get_text_list, smart_split, unescape_string_literal,
)
from django.utils.timezone import template_localtime
from django.utils.translation import gettext_lazy, pgettext_lazy
from .exceptions import TemplateSyntaxError
# template syntax constants
FILTER_SEPARATOR = "|"
FILTER_ARGUMENT_SEPARATOR = ":"
VARIABLE_ATTRIBUTE_SEPARATOR = "."
BLOCK_TAG_START = "{%"
BLOCK_TAG_END = "%}"
VARIABLE_TAG_START = "{{"
VARIABLE_TAG_END = "}}"
COMMENT_TAG_START = "{#"
COMMENT_TAG_END = "#}"
SINGLE_BRACE_START = "{"
SINGLE_BRACE_END = "}"
FILTER_SEPARATOR = '|'
FILTER_ARGUMENT_SEPARATOR = ':'
VARIABLE_ATTRIBUTE_SEPARATOR = '.'
BLOCK_TAG_START = '{%'
BLOCK_TAG_END = '%}'
VARIABLE_TAG_START = '{{'
VARIABLE_TAG_END = '}}'
COMMENT_TAG_START = '{#'
COMMENT_TAG_END = '#}'
TRANSLATOR_COMMENT_MARK = 'Translators'
SINGLE_BRACE_START = '{'
SINGLE_BRACE_END = '}'
# what to report as the origin for templates that come from non-loader sources
# (e.g. strings)
UNKNOWN_SOURCE = "<unknown source>"
UNKNOWN_SOURCE = '<unknown source>'
# Match BLOCK_TAG_*, VARIABLE_TAG_*, and COMMENT_TAG_* tags and capture the
# entire tag, including start/end delimiters. Using re.compile() is faster
# than instantiating SimpleLazyObject with _lazy_re_compile().
tag_re = re.compile(r"({%.*?%}|{{.*?}}|{#.*?#})")
# match a variable or block tag and capture the entire tag, including start/end
# delimiters
tag_re = (_lazy_re_compile('(%s.*?%s|%s.*?%s|%s.*?%s)' %
(re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END),
re.escape(COMMENT_TAG_START), re.escape(COMMENT_TAG_END))))
logger = logging.getLogger("django.template")
logger = logging.getLogger('django.template')
class TokenType(Enum):
@@ -99,6 +104,7 @@ class TokenType(Enum):
class VariableDoesNotExist(Exception):
def __init__(self, msg, params=()):
self.msg = msg
self.params = params
@@ -116,22 +122,18 @@ class Origin:
def __str__(self):
return self.name
def __repr__(self):
return "<%s name=%r>" % (self.__class__.__qualname__, self.name)
def __eq__(self, other):
return (
isinstance(other, Origin)
and self.name == other.name
and self.loader == other.loader
isinstance(other, Origin) and
self.name == other.name and
self.loader == other.loader
)
@property
def loader_name(self):
if self.loader:
return "%s.%s" % (
self.loader.__module__,
self.loader.__class__.__name__,
return '%s.%s' % (
self.loader.__module__, self.loader.__class__.__name__,
)
@@ -143,7 +145,6 @@ class Template:
# e.g. Template('...').render(Context({...}))
if engine is None:
from .engine import Engine
engine = Engine.get_default()
if origin is None:
origin = Origin(UNKNOWN_SOURCE)
@@ -157,12 +158,6 @@ class Template:
for node in self.nodelist:
yield from node
def __repr__(self):
return '<%s template_string="%s...">' % (
self.__class__.__qualname__,
self.source[:20].replace("\n", ""),
)
def _render(self, context):
return self.nodelist.render(context)
@@ -190,9 +185,7 @@ class Template:
tokens = lexer.tokenize()
parser = Parser(
tokens,
self.engine.template_libraries,
self.engine.template_builtins,
tokens, self.engine.template_libraries, self.engine.template_builtins,
self.origin,
)
@@ -264,30 +257,30 @@ class Template:
try:
message = str(exception.args[0])
except (IndexError, UnicodeDecodeError):
message = "(Could not get exception message)"
message = '(Could not get exception message)'
return {
"message": message,
"source_lines": source_lines[top:bottom],
"before": before,
"during": during,
"after": after,
"top": top,
"bottom": bottom,
"total": total,
"line": line,
"name": self.origin.name,
"start": start,
"end": end,
'message': message,
'source_lines': source_lines[top:bottom],
'before': before,
'during': during,
'after': after,
'top': top,
'bottom': bottom,
'total': total,
'line': line,
'name': self.origin.name,
'start': start,
'end': end,
}
def linebreak_iter(template_source):
yield 0
p = template_source.find("\n")
p = template_source.find('\n')
while p >= 0:
yield p + 1
p = template_source.find("\n", p + 1)
p = template_source.find('\n', p + 1)
yield len(template_source) + 1
@@ -315,12 +308,10 @@ class Token:
self.lineno = lineno
self.position = position
def __repr__(self):
def __str__(self):
token_name = self.token_type.name.capitalize()
return '<%s token: "%s...">' % (
token_name,
self.contents[:20].replace("\n", ""),
)
return ('<%s token: "%s...">' %
(token_name, self.contents[:20].replace('\n', '')))
def split_contents(self):
split = []
@@ -328,12 +319,12 @@ class Token:
for bit in bits:
# Handle translation-marked template pieces
if bit.startswith(('_("', "_('")):
sentinel = bit[2] + ")"
sentinel = bit[2] + ')'
trans_bit = [bit]
while not bit.endswith(sentinel):
bit = next(bits)
trans_bit.append(bit)
bit = " ".join(trans_bit)
bit = ' '.join(trans_bit)
split.append(bit)
return split
@@ -343,13 +334,6 @@ class Lexer:
self.template_string = template_string
self.verbatim = False
def __repr__(self):
return '<%s template_string="%s...", verbatim=%s>' % (
self.__class__.__qualname__,
self.template_string[:20].replace("\n", ""),
self.verbatim,
)
def tokenize(self):
"""
Return a list of tokens from a given template_string.
@@ -357,11 +341,11 @@ class Lexer:
in_tag = False
lineno = 1
result = []
for token_string in tag_re.split(self.template_string):
if token_string:
result.append(self.create_token(token_string, None, lineno, in_tag))
lineno += token_string.count("\n")
for bit in tag_re.split(self.template_string):
if bit:
result.append(self.create_token(bit, None, lineno, in_tag))
in_tag = not in_tag
lineno += bit.count('\n')
return result
def create_token(self, token_string, position, lineno, in_tag):
@@ -370,66 +354,53 @@ class Lexer:
If in_tag is True, we are processing something that matched a tag,
otherwise it should be treated as a literal string.
"""
if in_tag:
# The [0:2] and [2:-2] ranges below strip off *_TAG_START and
# *_TAG_END. The 2's are hard-coded for performance. Using
# len(BLOCK_TAG_START) would permit BLOCK_TAG_START to be
# different, but it's not likely that the TAG_START values will
# change anytime soon.
token_start = token_string[0:2]
if token_start == BLOCK_TAG_START:
content = token_string[2:-2].strip()
if self.verbatim:
# Then a verbatim block is being processed.
if content != self.verbatim:
return Token(TokenType.TEXT, token_string, position, lineno)
# Otherwise, the current verbatim block is ending.
self.verbatim = False
elif content[:9] in ("verbatim", "verbatim "):
# Then a verbatim block is starting.
self.verbatim = "end%s" % content
return Token(TokenType.BLOCK, content, position, lineno)
if not self.verbatim:
content = token_string[2:-2].strip()
if token_start == VARIABLE_TAG_START:
return Token(TokenType.VAR, content, position, lineno)
# BLOCK_TAG_START was handled above.
assert token_start == COMMENT_TAG_START
if in_tag and token_string.startswith(BLOCK_TAG_START):
# The [2:-2] ranges below strip off *_TAG_START and *_TAG_END.
# We could do len(BLOCK_TAG_START) to be more "correct", but we've
# hard-coded the 2s here for performance. And it's not like
# the TAG_START values are going to change anytime, anyway.
block_content = token_string[2:-2].strip()
if self.verbatim and block_content == self.verbatim:
self.verbatim = False
if in_tag and not self.verbatim:
if token_string.startswith(VARIABLE_TAG_START):
return Token(TokenType.VAR, token_string[2:-2].strip(), position, lineno)
elif token_string.startswith(BLOCK_TAG_START):
if block_content[:9] in ('verbatim', 'verbatim '):
self.verbatim = 'end%s' % block_content
return Token(TokenType.BLOCK, block_content, position, lineno)
elif token_string.startswith(COMMENT_TAG_START):
content = ''
if token_string.find(TRANSLATOR_COMMENT_MARK):
content = token_string[2:-2].strip()
return Token(TokenType.COMMENT, content, position, lineno)
return Token(TokenType.TEXT, token_string, position, lineno)
else:
return Token(TokenType.TEXT, token_string, position, lineno)
class DebugLexer(Lexer):
def _tag_re_split_positions(self):
last = 0
for match in tag_re.finditer(self.template_string):
start, end = match.span()
yield last, start
yield start, end
last = end
yield last, len(self.template_string)
# This parallels the use of tag_re.split() in Lexer.tokenize().
def _tag_re_split(self):
for position in self._tag_re_split_positions():
yield self.template_string[slice(*position)], position
def tokenize(self):
"""
Split a template string into tokens and annotates each token with its
start and end position in the source. This is slower than the default
lexer so only use it when debug is True.
"""
# For maintainability, it is helpful if the implementation below can
# continue to closely parallel Lexer.tokenize()'s implementation.
in_tag = False
lineno = 1
result = []
for token_string, position in self._tag_re_split():
if token_string:
result.append(self.create_token(token_string, position, lineno, in_tag))
lineno += token_string.count("\n")
in_tag = not in_tag
upto = 0
for match in tag_re.finditer(self.template_string):
start, end = match.span()
if start > upto:
token_string = self.template_string[upto:start]
result.append(self.create_token(token_string, (upto, start), lineno, in_tag=False))
lineno += token_string.count('\n')
token_string = self.template_string[start:end]
result.append(self.create_token(token_string, (start, end), lineno, in_tag=True))
lineno += token_string.count('\n')
upto = end
last_bit = self.template_string[upto:]
if last_bit:
result.append(self.create_token(last_bit, (upto, upto + len(last_bit)), lineno, in_tag=False))
return result
@@ -452,9 +423,6 @@ class Parser:
self.add_library(builtin)
self.origin = origin
def __repr__(self):
return "<%s tokens=%r>" % (self.__class__.__qualname__, self.tokens)
def parse(self, parse_until=None):
"""
Iterate through the parser tokens and compiles each one into a node.
@@ -470,25 +438,22 @@ class Parser:
while self.tokens:
token = self.next_token()
# Use the raw values here for TokenType.* for a tiny performance boost.
token_type = token.token_type.value
if token_type == 0: # TokenType.TEXT
if token.token_type.value == 0: # TokenType.TEXT
self.extend_nodelist(nodelist, TextNode(token.contents), token)
elif token_type == 1: # TokenType.VAR
elif token.token_type.value == 1: # TokenType.VAR
if not token.contents:
raise self.error(
token, "Empty variable tag on line %d" % token.lineno
)
raise self.error(token, 'Empty variable tag on line %d' % token.lineno)
try:
filter_expression = self.compile_filter(token.contents)
except TemplateSyntaxError as e:
raise self.error(token, e)
var_node = VariableNode(filter_expression)
self.extend_nodelist(nodelist, var_node, token)
elif token_type == 2: # TokenType.BLOCK
elif token.token_type.value == 2: # TokenType.BLOCK
try:
command = token.contents.split()[0]
except IndexError:
raise self.error(token, "Empty block tag on line %d" % token.lineno)
raise self.error(token, 'Empty block tag on line %d' % token.lineno)
if command in parse_until:
# A matching token has been reached. Return control to
# the caller. Put the token back on the token list so the
@@ -529,10 +494,9 @@ class Parser:
# Check that non-text nodes don't appear before an extends tag.
if node.must_be_first and nodelist.contains_nontext:
raise self.error(
token,
"%r must be the first tag in the template." % node,
token, '%r must be the first tag in the template.' % node,
)
if not isinstance(node, TextNode):
if isinstance(nodelist, NodeList) and not isinstance(node, TextNode):
nodelist.contains_nontext = True
# Set origin and token here since we can't modify the node __init__()
# method.
@@ -549,7 +513,7 @@ class Parser:
"""
if not isinstance(e, Exception):
e = TemplateSyntaxError(e)
if not hasattr(e, "token"):
if not hasattr(e, 'token'):
e.token = token
return e
@@ -558,17 +522,16 @@ class Parser:
raise self.error(
token,
"Invalid block tag on line %d: '%s', expected %s. Did you "
"forget to register or load this tag?"
% (
"forget to register or load this tag?" % (
token.lineno,
command,
get_text_list(["'%s'" % p for p in parse_until], "or"),
get_text_list(["'%s'" % p for p in parse_until], 'or'),
),
)
raise self.error(
token,
"Invalid block tag on line %d: '%s'. Did you forget to register "
"or load this tag?" % (token.lineno, command),
"or load this tag?" % (token.lineno, command)
)
def unclosed_block_tag(self, parse_until):
@@ -576,7 +539,7 @@ class Parser:
msg = "Unclosed tag on line %d: '%s'. Looking for one of: %s." % (
token.lineno,
command,
", ".join(parse_until),
', '.join(parse_until),
)
raise self.error(token, msg)
@@ -615,10 +578,10 @@ constant_string = r"""
%(strdq)s|
%(strsq)s)
""" % {
"strdq": r'"[^"\\]*(?:\\.[^"\\]*)*"', # double-quoted string
"strsq": r"'[^'\\]*(?:\\.[^'\\]*)*'", # single-quoted string
"i18n_open": re.escape("_("),
"i18n_close": re.escape(")"),
'strdq': r'"[^"\\]*(?:\\.[^"\\]*)*"', # double-quoted string
'strsq': r"'[^'\\]*(?:\\.[^'\\]*)*'", # single-quoted string
'i18n_open': re.escape("_("),
'i18n_close': re.escape(")"),
}
constant_string = constant_string.replace("\n", "")
@@ -634,11 +597,11 @@ filter_raw_string = r"""
)
)?
)""" % {
"constant": constant_string,
"num": r"[-+\.]?\d[\d\.e]*",
"var_chars": r"\w\.",
"filter_sep": re.escape(FILTER_SEPARATOR),
"arg_sep": re.escape(FILTER_ARGUMENT_SEPARATOR),
'constant': constant_string,
'num': r'[-+\.]?\d[\d\.e]*',
'var_chars': r'\w\.',
'filter_sep': re.escape(FILTER_SEPARATOR),
'arg_sep': re.escape(FILTER_ARGUMENT_SEPARATOR),
}
filter_re = _lazy_re_compile(filter_raw_string, re.VERBOSE)
@@ -658,7 +621,6 @@ class FilterExpression:
>>> fe.var
<Variable: 'variable'>
"""
def __init__(self, token, parser):
self.token = token
matches = filter_re.finditer(token)
@@ -668,27 +630,26 @@ class FilterExpression:
for match in matches:
start = match.start()
if upto != start:
raise TemplateSyntaxError(
"Could not parse some characters: "
"%s|%s|%s" % (token[:upto], token[upto:start], token[start:])
)
raise TemplateSyntaxError("Could not parse some characters: "
"%s|%s|%s" %
(token[:upto], token[upto:start],
token[start:]))
if var_obj is None:
var, constant = match["var"], match["constant"]
var, constant = match['var'], match['constant']
if constant:
try:
var_obj = Variable(constant).resolve({})
except VariableDoesNotExist:
var_obj = None
elif var is None:
raise TemplateSyntaxError(
"Could not find variable at start of %s." % token
)
raise TemplateSyntaxError("Could not find variable at "
"start of %s." % token)
else:
var_obj = Variable(var)
else:
filter_name = match["filter_name"]
filter_name = match['filter_name']
args = []
constant_arg, var_arg = match["constant_arg"], match["var_arg"]
constant_arg, var_arg = match['constant_arg'], match['var_arg']
if constant_arg:
args.append((False, Variable(constant_arg).resolve({})))
elif var_arg:
@@ -698,10 +659,8 @@ class FilterExpression:
filters.append((filter_func, args))
upto = match.end()
if upto != len(token):
raise TemplateSyntaxError(
"Could not parse the remainder: '%s' "
"from '%s'" % (token[upto:], token)
)
raise TemplateSyntaxError("Could not parse the remainder: '%s' "
"from '%s'" % (token[upto:], token))
self.filters = filters
self.var = var_obj
@@ -716,7 +675,7 @@ class FilterExpression:
else:
string_if_invalid = context.template.engine.string_if_invalid
if string_if_invalid:
if "%s" in string_if_invalid:
if '%s' in string_if_invalid:
return string_if_invalid % self.var
else:
return string_if_invalid
@@ -731,13 +690,13 @@ class FilterExpression:
arg_vals.append(mark_safe(arg))
else:
arg_vals.append(arg.resolve(context))
if getattr(func, "expects_localtime", False):
if getattr(func, 'expects_localtime', False):
obj = template_localtime(obj, context.use_tz)
if getattr(func, "needs_autoescape", False):
if getattr(func, 'needs_autoescape', False):
new_obj = func(obj, autoescape=context.autoescape, *arg_vals)
else:
new_obj = func(obj, *arg_vals)
if getattr(func, "is_safe", False) and isinstance(obj, SafeData):
if getattr(func, 'is_safe', False) and isinstance(obj, SafeData):
obj = mark_safe(new_obj)
else:
obj = new_obj
@@ -755,20 +714,15 @@ class FilterExpression:
dlen = len(defaults or [])
# Not enough OR Too many
if plen < (alen - dlen) or plen > alen:
raise TemplateSyntaxError(
"%s requires %d arguments, %d provided" % (name, alen - dlen, plen)
)
raise TemplateSyntaxError("%s requires %d arguments, %d provided" %
(name, alen - dlen, plen))
return True
args_check = staticmethod(args_check)
def __str__(self):
return self.token
def __repr__(self):
return "<%s %r>" % (self.__class__.__qualname__, self.token)
class Variable:
"""
@@ -797,7 +751,8 @@ class Variable:
self.message_context = None
if not isinstance(var, str):
raise TypeError("Variable must be a string or number, got %s" % type(var))
raise TypeError(
"Variable must be a string or number, got %s" % type(var))
try:
# First try to treat this variable as a number.
#
@@ -807,16 +762,16 @@ class Variable:
# Try to interpret values containing a period or an 'e'/'E'
# (possibly scientific notation) as a float; otherwise, try int.
if "." in var or "e" in var.lower():
if '.' in var or 'e' in var.lower():
self.literal = float(var)
# "2." is invalid
if var[-1] == ".":
if var.endswith('.'):
raise ValueError
else:
self.literal = int(var)
except ValueError:
# A ValueError means that the variable isn't a number.
if var[0:2] == "_(" and var[-1] == ")":
if var.startswith('_(') and var.endswith(')'):
# The result of the lookup should be translated at rendering
# time.
self.translate = True
@@ -828,11 +783,10 @@ class Variable:
except ValueError:
# Otherwise we'll set self.lookups so that resolve() knows we're
# dealing with a bonafide variable
if VARIABLE_ATTRIBUTE_SEPARATOR + "_" in var or var[0] == "_":
raise TemplateSyntaxError(
"Variables and attributes may "
"not begin with underscores: '%s'" % var
)
if var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or var[0] == '_':
raise TemplateSyntaxError("Variables and attributes may "
"not begin with underscores: '%s'" %
var)
self.lookups = tuple(var.split(VARIABLE_ATTRIBUTE_SEPARATOR))
def resolve(self, context):
@@ -845,7 +799,7 @@ class Variable:
value = self.literal
if self.translate:
is_safe = isinstance(value, SafeData)
msgid = value.replace("%", "%%")
msgid = value.replace('%', '%%')
msgid = mark_safe(msgid) if is_safe else msgid
if self.message_context:
return pgettext_lazy(self.message_context, msgid)
@@ -878,9 +832,7 @@ class Variable:
except (TypeError, AttributeError, KeyError, ValueError, IndexError):
try: # attribute lookup
# Don't return class attributes if the class is the context:
if isinstance(current, BaseContext) and getattr(
type(current), bit
):
if isinstance(current, BaseContext) and getattr(type(current), bit):
raise AttributeError
current = getattr(current, bit)
except (TypeError, AttributeError):
@@ -889,20 +841,17 @@ class Variable:
raise
try: # list-index lookup
current = current[int(bit)]
except (
IndexError, # list index out of range
ValueError, # invalid literal for int()
KeyError, # current is a dict without `int(bit)` key
TypeError,
): # unsubscriptable object
raise VariableDoesNotExist(
"Failed lookup for key [%s] in %r",
(bit, current),
) # missing attribute
except (IndexError, # list index out of range
ValueError, # invalid literal for int()
KeyError, # current is a dict without `int(bit)` key
TypeError): # unsubscriptable object
raise VariableDoesNotExist("Failed lookup for key "
"[%s] in %r",
(bit, current)) # missing attribute
if callable(current):
if getattr(current, "do_not_call_in_templates", False):
if getattr(current, 'do_not_call_in_templates', False):
pass
elif getattr(current, "alters_data", False):
elif getattr(current, 'alters_data', False):
current = context.template.engine.string_if_invalid
else:
try: # method call (assuming no args required)
@@ -912,13 +861,11 @@ class Variable:
try:
signature.bind()
except TypeError: # arguments *were* required
current = (
context.template.engine.string_if_invalid
) # invalid method call
current = context.template.engine.string_if_invalid # invalid method call
else:
raise
except Exception as e:
template_name = getattr(context, "template_name", None) or "unknown"
template_name = getattr(context, 'template_name', None) or 'unknown'
logger.debug(
"Exception while resolving variable '%s' in template '%s'.",
bit,
@@ -926,7 +873,7 @@ class Variable:
exc_info=True,
)
if getattr(e, "silent_variable_failure", False):
if getattr(e, 'silent_variable_failure', False):
current = context.template.engine.string_if_invalid
else:
raise
@@ -938,7 +885,7 @@ class Node:
# Set this to True for nodes that must be first in the template (although
# they can be preceded by text nodes.
must_be_first = False
child_nodelists = ("nodelist",)
child_nodelists = ('nodelist',)
token = None
def render(self, context):
@@ -957,20 +904,8 @@ class Node:
try:
return self.render(context)
except Exception as e:
if context.template.engine.debug:
# Store the actual node that caused the exception.
if not hasattr(e, "_culprit_node"):
e._culprit_node = self
if (
not hasattr(e, "template_debug")
and context.render_context.template.origin == e._culprit_node.origin
):
e.template_debug = (
context.render_context.template.get_exception_info(
e,
e._culprit_node.token,
)
)
if context.template.engine.debug and not hasattr(e, 'template_debug'):
e.template_debug = context.render_context.template.get_exception_info(e, self.token)
raise
def __iter__(self):
@@ -997,7 +932,14 @@ class NodeList(list):
contains_nontext = False
def render(self, context):
return SafeString("".join([node.render_annotated(context) for node in self]))
bits = []
for node in self:
if isinstance(node, Node):
bit = node.render_annotated(context)
else:
bit = node
bits.append(str(bit))
return mark_safe(''.join(bits))
def get_nodes_by_type(self, nodetype):
"Return a list of all nodes of the given type"
@@ -1008,8 +950,6 @@ class NodeList(list):
class TextNode(Node):
child_nodelists = ()
def __init__(self, s):
self.s = s
@@ -1019,15 +959,6 @@ class TextNode(Node):
def render(self, context):
return self.s
def render_annotated(self, context):
"""
Return the given value.
The default implementation of this method handles exceptions raised
during rendering, which is not necessary for text nodes.
"""
return self.s
def render_value_in_context(value, context):
"""
@@ -1046,8 +977,6 @@ def render_value_in_context(value, context):
class VariableNode(Node):
child_nodelists = ()
def __init__(self, filter_expression):
self.filter_expression = filter_expression
@@ -1061,7 +990,7 @@ class VariableNode(Node):
# Unicode conversion can fail sometimes for reasons out of our
# control (e.g. exception rendering). In that case, we fail
# quietly.
return ""
return ''
return render_value_in_context(output, context)
@@ -1092,7 +1021,7 @@ def token_kwargs(bits, parser, support_legacy=False):
if not kwarg_format:
if not support_legacy:
return {}
if len(bits) < 3 or bits[1] != "as":
if len(bits) < 3 or bits[1] != 'as':
return {}
kwargs = {}
@@ -1104,13 +1033,13 @@ def token_kwargs(bits, parser, support_legacy=False):
key, value = match.groups()
del bits[:1]
else:
if len(bits) < 3 or bits[1] != "as":
if len(bits) < 3 or bits[1] != 'as':
return kwargs
key, value = bits[2], bits[0]
del bits[:3]
kwargs[key] = parser.compile_filter(value)
if bits and not kwarg_format:
if bits[0] != "and":
if bits[0] != 'and':
return kwargs
del bits[:1]
return kwargs