Convert watch page to flask framework
This commit is contained in:
220
python/jinja2/nativetypes.py
Normal file
220
python/jinja2/nativetypes.py
Normal file
@@ -0,0 +1,220 @@
|
||||
import sys
|
||||
from ast import literal_eval
|
||||
from itertools import islice, chain
|
||||
from jinja2 import nodes
|
||||
from jinja2._compat import text_type
|
||||
from jinja2.compiler import CodeGenerator, has_safe_repr
|
||||
from jinja2.environment import Environment, Template
|
||||
from jinja2.utils import concat, escape
|
||||
|
||||
|
||||
def native_concat(nodes):
|
||||
"""Return a native Python type from the list of compiled nodes. If the
|
||||
result is a single node, its value is returned. Otherwise, the nodes are
|
||||
concatenated as strings. If the result can be parsed with
|
||||
:func:`ast.literal_eval`, the parsed value is returned. Otherwise, the
|
||||
string is returned.
|
||||
"""
|
||||
head = list(islice(nodes, 2))
|
||||
|
||||
if not head:
|
||||
return None
|
||||
|
||||
if len(head) == 1:
|
||||
out = head[0]
|
||||
else:
|
||||
out = u''.join([text_type(v) for v in chain(head, nodes)])
|
||||
|
||||
try:
|
||||
return literal_eval(out)
|
||||
except (ValueError, SyntaxError, MemoryError):
|
||||
return out
|
||||
|
||||
|
||||
class NativeCodeGenerator(CodeGenerator):
|
||||
"""A code generator which avoids injecting ``to_string()`` calls around the
|
||||
internal code Jinja uses to render templates.
|
||||
"""
|
||||
|
||||
def visit_Output(self, node, frame):
|
||||
"""Same as :meth:`CodeGenerator.visit_Output`, but do not call
|
||||
``to_string`` on output nodes in generated code.
|
||||
"""
|
||||
if self.has_known_extends and frame.require_output_check:
|
||||
return
|
||||
|
||||
finalize = self.environment.finalize
|
||||
finalize_context = getattr(finalize, 'contextfunction', False)
|
||||
finalize_eval = getattr(finalize, 'evalcontextfunction', False)
|
||||
finalize_env = getattr(finalize, 'environmentfunction', False)
|
||||
|
||||
if finalize is not None:
|
||||
if finalize_context or finalize_eval:
|
||||
const_finalize = None
|
||||
elif finalize_env:
|
||||
def const_finalize(x):
|
||||
return finalize(self.environment, x)
|
||||
else:
|
||||
const_finalize = finalize
|
||||
else:
|
||||
def const_finalize(x):
|
||||
return x
|
||||
|
||||
# If we are inside a frame that requires output checking, we do so.
|
||||
outdent_later = False
|
||||
|
||||
if frame.require_output_check:
|
||||
self.writeline('if parent_template is None:')
|
||||
self.indent()
|
||||
outdent_later = True
|
||||
|
||||
# Try to evaluate as many chunks as possible into a static string at
|
||||
# compile time.
|
||||
body = []
|
||||
|
||||
for child in node.nodes:
|
||||
try:
|
||||
if const_finalize is None:
|
||||
raise nodes.Impossible()
|
||||
|
||||
const = child.as_const(frame.eval_ctx)
|
||||
if not has_safe_repr(const):
|
||||
raise nodes.Impossible()
|
||||
except nodes.Impossible:
|
||||
body.append(child)
|
||||
continue
|
||||
|
||||
# the frame can't be volatile here, because otherwise the as_const
|
||||
# function would raise an Impossible exception at that point
|
||||
try:
|
||||
if frame.eval_ctx.autoescape:
|
||||
if hasattr(const, '__html__'):
|
||||
const = const.__html__()
|
||||
else:
|
||||
const = escape(const)
|
||||
|
||||
const = const_finalize(const)
|
||||
except Exception:
|
||||
# if something goes wrong here we evaluate the node at runtime
|
||||
# for easier debugging
|
||||
body.append(child)
|
||||
continue
|
||||
|
||||
if body and isinstance(body[-1], list):
|
||||
body[-1].append(const)
|
||||
else:
|
||||
body.append([const])
|
||||
|
||||
# if we have less than 3 nodes or a buffer we yield or extend/append
|
||||
if len(body) < 3 or frame.buffer is not None:
|
||||
if frame.buffer is not None:
|
||||
# for one item we append, for more we extend
|
||||
if len(body) == 1:
|
||||
self.writeline('%s.append(' % frame.buffer)
|
||||
else:
|
||||
self.writeline('%s.extend((' % frame.buffer)
|
||||
|
||||
self.indent()
|
||||
|
||||
for item in body:
|
||||
if isinstance(item, list):
|
||||
val = repr(native_concat(item))
|
||||
|
||||
if frame.buffer is None:
|
||||
self.writeline('yield ' + val)
|
||||
else:
|
||||
self.writeline(val + ',')
|
||||
else:
|
||||
if frame.buffer is None:
|
||||
self.writeline('yield ', item)
|
||||
else:
|
||||
self.newline(item)
|
||||
|
||||
close = 0
|
||||
|
||||
if finalize is not None:
|
||||
self.write('environment.finalize(')
|
||||
|
||||
if finalize_context:
|
||||
self.write('context, ')
|
||||
|
||||
close += 1
|
||||
|
||||
self.visit(item, frame)
|
||||
|
||||
if close > 0:
|
||||
self.write(')' * close)
|
||||
|
||||
if frame.buffer is not None:
|
||||
self.write(',')
|
||||
|
||||
if frame.buffer is not None:
|
||||
# close the open parentheses
|
||||
self.outdent()
|
||||
self.writeline(len(body) == 1 and ')' or '))')
|
||||
|
||||
# otherwise we create a format string as this is faster in that case
|
||||
else:
|
||||
format = []
|
||||
arguments = []
|
||||
|
||||
for item in body:
|
||||
if isinstance(item, list):
|
||||
format.append(native_concat(item).replace('%', '%%'))
|
||||
else:
|
||||
format.append('%s')
|
||||
arguments.append(item)
|
||||
|
||||
self.writeline('yield ')
|
||||
self.write(repr(concat(format)) + ' % (')
|
||||
self.indent()
|
||||
|
||||
for argument in arguments:
|
||||
self.newline(argument)
|
||||
close = 0
|
||||
|
||||
if finalize is not None:
|
||||
self.write('environment.finalize(')
|
||||
|
||||
if finalize_context:
|
||||
self.write('context, ')
|
||||
elif finalize_eval:
|
||||
self.write('context.eval_ctx, ')
|
||||
elif finalize_env:
|
||||
self.write('environment, ')
|
||||
|
||||
close += 1
|
||||
|
||||
self.visit(argument, frame)
|
||||
self.write(')' * close + ', ')
|
||||
|
||||
self.outdent()
|
||||
self.writeline(')')
|
||||
|
||||
if outdent_later:
|
||||
self.outdent()
|
||||
|
||||
|
||||
class NativeTemplate(Template):
|
||||
def render(self, *args, **kwargs):
|
||||
"""Render the template to produce a native Python type. If the result
|
||||
is a single node, its value is returned. Otherwise, the nodes are
|
||||
concatenated as strings. If the result can be parsed with
|
||||
:func:`ast.literal_eval`, the parsed value is returned. Otherwise, the
|
||||
string is returned.
|
||||
"""
|
||||
vars = dict(*args, **kwargs)
|
||||
|
||||
try:
|
||||
return native_concat(self.root_render_func(self.new_context(vars)))
|
||||
except Exception:
|
||||
exc_info = sys.exc_info()
|
||||
|
||||
return self.environment.handle_exception(exc_info, True)
|
||||
|
||||
|
||||
class NativeEnvironment(Environment):
|
||||
"""An environment that renders templates to native Python types."""
|
||||
|
||||
code_generator_class = NativeCodeGenerator
|
||||
template_class = NativeTemplate
|
||||
Reference in New Issue
Block a user