From dcee83385444d8f37fd39721f49314f0f0efd3c8 Mon Sep 17 00:00:00 2001 From: James Addison Date: Sat, 18 Feb 2023 20:02:09 +0000 Subject: [PATCH] Revert "Revert "support native types in macros"" This reverts commit 84c183643c1f5acdeb74cfdf1fdfa7ef7fad4c71. --- src/jinja2/compiler.py | 1 + src/jinja2/environment.py | 8 ++++++-- src/jinja2/nativetypes.py | 12 +++++++++--- src/jinja2/runtime.py | 1 - tests/test_nativetypes.py | 7 +++++++ 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/jinja2/compiler.py b/src/jinja2/compiler.py index ffff4079d..7dfac0a71 100644 --- a/src/jinja2/compiler.py +++ b/src/jinja2/compiler.py @@ -724,6 +724,7 @@ def write_commons(self) -> None: """ self.writeline("resolve = context.resolve_or_missing") self.writeline("undefined = environment.undefined") + self.writeline("concat = environment.concat") # always use the standard Undefined class for the implicit else of # conditional expressions self.writeline("cond_expr_undefined = Undefined") diff --git a/src/jinja2/environment.py b/src/jinja2/environment.py index dc52131c4..29a1b4e40 100644 --- a/src/jinja2/environment.py +++ b/src/jinja2/environment.py @@ -283,6 +283,8 @@ class Environment: #: :class:`~jinja2.compiler.CodeGenerator` for more information. code_generator_class: t.Type["CodeGenerator"] = CodeGenerator + concat = "".join + #: the context class that is used for templates. See #: :class:`~jinja2.runtime.Context` for more information. context_class: t.Type[Context] = Context @@ -1296,7 +1298,7 @@ def render(self, *args: t.Any, **kwargs: t.Any) -> str: ctx = self.new_context(dict(*args, **kwargs)) try: - return concat(self.root_render_func(ctx)) # type: ignore + return self.environment.concat(self.root_render_func(ctx)) # type: ignore except Exception: self.environment.handle_exception() @@ -1317,7 +1319,9 @@ async def render_async(self, *args: t.Any, **kwargs: t.Any) -> str: ctx = self.new_context(dict(*args, **kwargs)) try: - return concat([n async for n in self.root_render_func(ctx)]) # type: ignore + return self.environment.concat( # type: ignore + [n async for n in self.root_render_func(ctx)] # type: ignore + ) except Exception: return self.environment.handle_exception() diff --git a/src/jinja2/nativetypes.py b/src/jinja2/nativetypes.py index 20597d50a..ac0861034 100644 --- a/src/jinja2/nativetypes.py +++ b/src/jinja2/nativetypes.py @@ -3,6 +3,7 @@ from ast import parse from itertools import chain from itertools import islice +from types import GeneratorType from . import nodes from .compiler import CodeGenerator @@ -31,7 +32,9 @@ def native_concat(values: t.Iterable[t.Any]) -> t.Optional[t.Any]: if not isinstance(raw, str): return raw else: - raw = "".join([str(v) for v in chain(head, values)]) + if isinstance(values, GeneratorType): + values = chain(head, values) + raw = "".join([str(v) for v in values]) try: return literal_eval( @@ -86,6 +89,7 @@ class NativeEnvironment(Environment): """An environment that renders templates to native Python types.""" code_generator_class = NativeCodeGenerator + concat = staticmethod(native_concat) # type: ignore class NativeTemplate(Template): @@ -101,7 +105,9 @@ def render(self, *args: t.Any, **kwargs: t.Any) -> t.Any: ctx = self.new_context(dict(*args, **kwargs)) try: - return native_concat(self.root_render_func(ctx)) # type: ignore + return self.environment_class.concat( # type: ignore + self.root_render_func(ctx) # type: ignore + ) except Exception: return self.environment.handle_exception() @@ -114,7 +120,7 @@ async def render_async(self, *args: t.Any, **kwargs: t.Any) -> t.Any: ctx = self.new_context(dict(*args, **kwargs)) try: - return native_concat( + return self.environment_class.concat( # type: ignore [n async for n in self.root_render_func(ctx)] # type: ignore ) except Exception: diff --git a/src/jinja2/runtime.py b/src/jinja2/runtime.py index fc19baaa2..c64999d9d 100644 --- a/src/jinja2/runtime.py +++ b/src/jinja2/runtime.py @@ -49,7 +49,6 @@ def __call__( "Markup", "TemplateRuntimeError", "missing", - "concat", "escape", "markup_join", "str_join", diff --git a/tests/test_nativetypes.py b/tests/test_nativetypes.py index e53db7e75..c784f8da6 100644 --- a/tests/test_nativetypes.py +++ b/tests/test_nativetypes.py @@ -168,3 +168,10 @@ def test_leading_spaces(env): t = env.from_string(" {{ True }}") result = t.render() assert result == " True" + + +def test_macro(env): + t = env.from_string("{%- macro x() -%}{{- [1,2] -}}{%- endmacro -%}{{- x()[1] -}}") + result = t.render() + assert result == 2 + assert isinstance(result, int)