Skip to content

Commit

Permalink
Add some very special quoting rules for rendering
Browse files Browse the repository at this point in the history
Handle quoting in render() instead of get_rendered code
 - avoid stripping the quotes from a string that was returned as jinja
  • Loading branch information
Jacob Beck committed Apr 27, 2020
1 parent 52cf845 commit 4c2968e
Showing 1 changed file with 46 additions and 7 deletions.
53 changes: 46 additions & 7 deletions core/dbt/clients/jinja.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import re
import tempfile
import threading
from ast import literal_eval
from contextlib import contextmanager
from itertools import chain, islice
from typing import (
List, Union, Set, Optional, Dict, Any, Iterator, Type, NoReturn
)
Expand Down Expand Up @@ -102,9 +104,51 @@ class NativeSandboxEnvironment(MacroFuzzEnvironment):
code_generator_class = jinja2.nativetypes.NativeCodeGenerator


def quoted_native_concat(nodes):
"""This is almost native_concat from the NativeTemplate, except in the
special case of a single argument that is a quoted string and returns a
string, the quotes are re-inserted.
"""
head = list(islice(nodes, 2))

if not head:
return None

if len(head) == 1:
raw = head[0]
else:
raw = "".join([str(v) for v in chain(head, nodes)])

try:
result = literal_eval(raw)
except (ValueError, SyntaxError, MemoryError):
return raw

if len(head) == 1 and len(raw) > 2 and isinstance(result, str):
return _requote_result(raw, result)
else:
return result


class NativeSandboxTemplate(jinja2.nativetypes.NativeTemplate): # mypy: ignore
environment_class = NativeSandboxEnvironment

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 quoted_native_concat(
self.root_render_func(self.new_context(vars))
)
except Exception:
return self.environment.handle_exception()


NativeSandboxEnvironment.template_class = NativeSandboxTemplate # type: ignore

Expand Down Expand Up @@ -425,7 +469,7 @@ def render_template(template, ctx: Dict[str, Any], node=None) -> str:
return template.render(ctx)


def _requote_result(raw_value, rendered):
def _requote_result(raw_value: str, rendered: str) -> str:
double_quoted = raw_value.startswith('"') and raw_value.endswith('"')
single_quoted = raw_value.startswith("'") and raw_value.endswith("'")
if double_quoted:
Expand All @@ -451,12 +495,7 @@ def get_rendered(
capture_macros=capture_macros,
native=native,
)

result = render_template(template, ctx, node)

if native and isinstance(result, str):
result = _requote_result(string, result)
return result
return render_template(template, ctx, node)


def undefined_error(msg) -> NoReturn:
Expand Down

0 comments on commit 4c2968e

Please sign in to comment.