jinja2.nativetypes

  1import typing as t
  2from ast import literal_eval
  3from ast import parse
  4from itertools import chain
  5from itertools import islice
  6from types import GeneratorType
  7
  8from . import nodes
  9from .compiler import CodeGenerator
 10from .compiler import Frame
 11from .compiler import has_safe_repr
 12from .environment import Environment
 13from .environment import Template
 14
 15
 16def native_concat(values: t.Iterable[t.Any]) -> t.Optional[t.Any]:
 17    """Return a native Python type from the list of compiled nodes. If
 18    the result is a single node, its value is returned. Otherwise, the
 19    nodes are concatenated as strings. If the result can be parsed with
 20    :func:`ast.literal_eval`, the parsed value is returned. Otherwise,
 21    the string is returned.
 22
 23    :param values: Iterable of outputs to concatenate.
 24    """
 25    head = list(islice(values, 2))
 26
 27    if not head:
 28        return None
 29
 30    if len(head) == 1:
 31        raw = head[0]
 32        if not isinstance(raw, str):
 33            return raw
 34    else:
 35        if isinstance(values, GeneratorType):
 36            values = chain(head, values)
 37        raw = "".join([str(v) for v in values])
 38
 39    try:
 40        return literal_eval(
 41            # In Python 3.10+ ast.literal_eval removes leading spaces/tabs
 42            # from the given string. For backwards compatibility we need to
 43            # parse the string ourselves without removing leading spaces/tabs.
 44            parse(raw, mode="eval")
 45        )
 46    except (ValueError, SyntaxError, MemoryError):
 47        return raw
 48
 49
 50class NativeCodeGenerator(CodeGenerator):
 51    """A code generator which renders Python types by not adding
 52    ``str()`` around output nodes.
 53    """
 54
 55    @staticmethod
 56    def _default_finalize(value: t.Any) -> t.Any:
 57        return value
 58
 59    def _output_const_repr(self, group: t.Iterable[t.Any]) -> str:
 60        return repr("".join([str(v) for v in group]))
 61
 62    def _output_child_to_const(
 63        self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
 64    ) -> t.Any:
 65        const = node.as_const(frame.eval_ctx)
 66
 67        if not has_safe_repr(const):
 68            raise nodes.Impossible()
 69
 70        if isinstance(node, nodes.TemplateData):
 71            return const
 72
 73        return finalize.const(const)  # type: ignore
 74
 75    def _output_child_pre(
 76        self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
 77    ) -> None:
 78        if finalize.src is not None:
 79            self.write(finalize.src)
 80
 81    def _output_child_post(
 82        self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
 83    ) -> None:
 84        if finalize.src is not None:
 85            self.write(")")
 86
 87
 88class NativeEnvironment(Environment):
 89    """An environment that renders templates to native Python types."""
 90
 91    code_generator_class = NativeCodeGenerator
 92    concat = staticmethod(native_concat)  # type: ignore
 93
 94
 95class NativeTemplate(Template):
 96    environment_class = NativeEnvironment
 97
 98    def render(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
 99        """Render the template to produce a native Python type. If the
100        result is a single node, its value is returned. Otherwise, the
101        nodes are concatenated as strings. If the result can be parsed
102        with :func:`ast.literal_eval`, the parsed value is returned.
103        Otherwise, the string is returned.
104        """
105        ctx = self.new_context(dict(*args, **kwargs))
106
107        try:
108            return self.environment_class.concat(  # type: ignore
109                self.root_render_func(ctx)
110            )
111        except Exception:
112            return self.environment.handle_exception()
113
114    async def render_async(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
115        if not self.environment.is_async:
116            raise RuntimeError(
117                "The environment was not created with async mode enabled."
118            )
119
120        ctx = self.new_context(dict(*args, **kwargs))
121
122        try:
123            return self.environment_class.concat(  # type: ignore
124                [n async for n in self.root_render_func(ctx)]  # type: ignore
125            )
126        except Exception:
127            return self.environment.handle_exception()
128
129
130NativeEnvironment.template_class = NativeTemplate
def native_concat(values: Iterable[Any]) -> Optional[Any]:
17def native_concat(values: t.Iterable[t.Any]) -> t.Optional[t.Any]:
18    """Return a native Python type from the list of compiled nodes. If
19    the result is a single node, its value is returned. Otherwise, the
20    nodes are concatenated as strings. If the result can be parsed with
21    :func:`ast.literal_eval`, the parsed value is returned. Otherwise,
22    the string is returned.
23
24    :param values: Iterable of outputs to concatenate.
25    """
26    head = list(islice(values, 2))
27
28    if not head:
29        return None
30
31    if len(head) == 1:
32        raw = head[0]
33        if not isinstance(raw, str):
34            return raw
35    else:
36        if isinstance(values, GeneratorType):
37            values = chain(head, values)
38        raw = "".join([str(v) for v in values])
39
40    try:
41        return literal_eval(
42            # In Python 3.10+ ast.literal_eval removes leading spaces/tabs
43            # from the given string. For backwards compatibility we need to
44            # parse the string ourselves without removing leading spaces/tabs.
45            parse(raw, mode="eval")
46        )
47    except (ValueError, SyntaxError, MemoryError):
48        return raw

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 ast.literal_eval(), the parsed value is returned. Otherwise, the string is returned.

Parameters
  • values: Iterable of outputs to concatenate.
class NativeCodeGenerator(jinja2.compiler.CodeGenerator):
51class NativeCodeGenerator(CodeGenerator):
52    """A code generator which renders Python types by not adding
53    ``str()`` around output nodes.
54    """
55
56    @staticmethod
57    def _default_finalize(value: t.Any) -> t.Any:
58        return value
59
60    def _output_const_repr(self, group: t.Iterable[t.Any]) -> str:
61        return repr("".join([str(v) for v in group]))
62
63    def _output_child_to_const(
64        self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
65    ) -> t.Any:
66        const = node.as_const(frame.eval_ctx)
67
68        if not has_safe_repr(const):
69            raise nodes.Impossible()
70
71        if isinstance(node, nodes.TemplateData):
72            return const
73
74        return finalize.const(const)  # type: ignore
75
76    def _output_child_pre(
77        self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
78    ) -> None:
79        if finalize.src is not None:
80            self.write(finalize.src)
81
82    def _output_child_post(
83        self, node: nodes.Expr, frame: Frame, finalize: CodeGenerator._FinalizeInfo
84    ) -> None:
85        if finalize.src is not None:
86            self.write(")")

A code generator which renders Python types by not adding str() around output nodes.

Inherited Members
jinja2.compiler.CodeGenerator
CodeGenerator
environment
name
filename
stream
created_block_context
defer_init
optimizer
import_aliases
blocks
extends_so_far
has_known_extends
code_lineno
tests
filters
debug_info
optimized
fail
temporary_identifier
buffer
return_buffer_contents
indent
outdent
start_write
end_write
simple_write
blockvisit
write
writeline
newline
signature
pull_dependencies
enter_frame
leave_frame
choose_async
func
macro_body
macro_def
position
dump_local_context
write_commons
push_parameter_definitions
pop_parameter_definitions
mark_parameter_stored
push_context_reference
pop_context_reference
get_context_ref
get_resolve_func
derive_context
parameter_is_undeclared
push_assign_tracking
pop_assign_tracking
visit_Template
visit_Block
visit_Extends
visit_Include
visit_Import
visit_FromImport
visit_For
visit_If
visit_Macro
visit_CallBlock
visit_FilterBlock
visit_With
visit_ExprStmt
visit_Output
visit_Assign
visit_AssignBlock
visit_Name
visit_NSRef
visit_Const
visit_TemplateData
visit_Tuple
visit_List
visit_Dict
visit_Add
visit_Sub
visit_Mul
visit_Div
visit_FloorDiv
visit_Pow
visit_Mod
visit_And
visit_Or
visit_Pos
visit_Neg
visit_Not
visit_Concat
visit_Compare
visit_Operand
visit_Getattr
visit_Getitem
visit_Slice
visit_Filter
visit_Test
visit_CondExpr
visit_Call
visit_Keyword
visit_MarkSafe
visit_MarkSafeIfAutoescape
visit_EnvironmentAttribute
visit_ExtensionAttribute
visit_ImportedName
visit_InternalName
visit_ContextReference
visit_DerivedContextReference
visit_Continue
visit_Break
visit_Scope
visit_OverlayScope
visit_EvalContextModifier
visit_ScopedEvalContextModifier
jinja2.visitor.NodeVisitor
get_visitor
visit
generic_visit
class NativeEnvironment(jinja2.environment.Environment):
89class NativeEnvironment(Environment):
90    """An environment that renders templates to native Python types."""
91
92    code_generator_class = NativeCodeGenerator
93    concat = staticmethod(native_concat)  # type: ignore

An environment that renders templates to native Python types.

code_generator_class = <class 'NativeCodeGenerator'>
def concat(values: Iterable[Any]) -> Optional[Any]:
17def native_concat(values: t.Iterable[t.Any]) -> t.Optional[t.Any]:
18    """Return a native Python type from the list of compiled nodes. If
19    the result is a single node, its value is returned. Otherwise, the
20    nodes are concatenated as strings. If the result can be parsed with
21    :func:`ast.literal_eval`, the parsed value is returned. Otherwise,
22    the string is returned.
23
24    :param values: Iterable of outputs to concatenate.
25    """
26    head = list(islice(values, 2))
27
28    if not head:
29        return None
30
31    if len(head) == 1:
32        raw = head[0]
33        if not isinstance(raw, str):
34            return raw
35    else:
36        if isinstance(values, GeneratorType):
37            values = chain(head, values)
38        raw = "".join([str(v) for v in values])
39
40    try:
41        return literal_eval(
42            # In Python 3.10+ ast.literal_eval removes leading spaces/tabs
43            # from the given string. For backwards compatibility we need to
44            # parse the string ourselves without removing leading spaces/tabs.
45            parse(raw, mode="eval")
46        )
47    except (ValueError, SyntaxError, MemoryError):
48        return raw

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 ast.literal_eval(), the parsed value is returned. Otherwise, the string is returned.

Parameters
  • values: Iterable of outputs to concatenate.
template_class: Type[jinja2.environment.Template] = <class 'NativeTemplate'>
class NativeTemplate(jinja2.environment.Template):
 96class NativeTemplate(Template):
 97    environment_class = NativeEnvironment
 98
 99    def render(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
100        """Render the template to produce a native Python type. If the
101        result is a single node, its value is returned. Otherwise, the
102        nodes are concatenated as strings. If the result can be parsed
103        with :func:`ast.literal_eval`, the parsed value is returned.
104        Otherwise, the string is returned.
105        """
106        ctx = self.new_context(dict(*args, **kwargs))
107
108        try:
109            return self.environment_class.concat(  # type: ignore
110                self.root_render_func(ctx)
111            )
112        except Exception:
113            return self.environment.handle_exception()
114
115    async def render_async(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
116        if not self.environment.is_async:
117            raise RuntimeError(
118                "The environment was not created with async mode enabled."
119            )
120
121        ctx = self.new_context(dict(*args, **kwargs))
122
123        try:
124            return self.environment_class.concat(  # type: ignore
125                [n async for n in self.root_render_func(ctx)]  # type: ignore
126            )
127        except Exception:
128            return self.environment.handle_exception()

A compiled template that can be rendered.

Use the methods on Environment to create or load templates. The environment is used to configure how templates are compiled and behave.

It is also possible to create a template object directly. This is not usually recommended. The constructor takes most of the same arguments as Environment. All templates created with the same environment arguments share the same ephemeral Environment instance behind the scenes.

A template object should be considered immutable. Modifications on the object are not supported.

environment_class = <class 'NativeEnvironment'>
def render(self, *args: Any, **kwargs: Any) -> Any:
 99    def render(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
100        """Render the template to produce a native Python type. If the
101        result is a single node, its value is returned. Otherwise, the
102        nodes are concatenated as strings. If the result can be parsed
103        with :func:`ast.literal_eval`, the parsed value is returned.
104        Otherwise, the string is returned.
105        """
106        ctx = self.new_context(dict(*args, **kwargs))
107
108        try:
109            return self.environment_class.concat(  # type: ignore
110                self.root_render_func(ctx)
111            )
112        except Exception:
113            return self.environment.handle_exception()

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 ast.literal_eval(), the parsed value is returned. Otherwise, the string is returned.

async def render_async(self, *args: Any, **kwargs: Any) -> Any:
115    async def render_async(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
116        if not self.environment.is_async:
117            raise RuntimeError(
118                "The environment was not created with async mode enabled."
119            )
120
121        ctx = self.new_context(dict(*args, **kwargs))
122
123        try:
124            return self.environment_class.concat(  # type: ignore
125                [n async for n in self.root_render_func(ctx)]  # type: ignore
126            )
127        except Exception:
128            return self.environment.handle_exception()

This works similar to render() but returns a coroutine that when awaited returns the entire rendered template string. This requires the async feature to be enabled.

Example usage::

await template.render_async(knights='that say nih; asynchronously')