Repository: dbt-labs/dbt-core

Issue:
Fix the build in dev/octavius-catto
### Describe the bug
It looks like a recent regression in `dev/octavius-catto` is causing [automated tests to fail](https://app.circleci.com/pipelines/github/fishtown-analytics/dbt/139/workflows/4978f30b-7313-4ac5-83ba-20e13fcb6624/jobs/23684). I think the error was introduced in https://github.com/fishtown-analytics/dbt/commit/f07face7c00b070518148e2fb34068dfedfe7fe2, but it's hard to say exactly where the issue is.

I don't know what the root cause is exactly, but it manifests as this schema test failing with a compilation exception:

https://github.com/fishtown-analytics/dbt/blob/d2760d5a494b81f6d477a67738ecdc37facdd5ec/test/integration/022_bigquery_test/dp-models/schema.yml#L9-L33

Upon further analysis, the cryptic error that we see in the test suite is a function of `*conf_columns` being copied by reference. When dbt gets to parsing the `confirmation_noconfig` model, the test for that model is already built-out with kwargs added from the `confirmation` model. Pretty strange failure mode....

### Steps To Reproduce
Run the test suite




Discussion:

Resolving patch:
diff --git a/core/dbt/clients/jinja.py b/core/dbt/clients/jinja.py
--- a/core/dbt/clients/jinja.py
+++ b/core/dbt/clients/jinja.py
@@ -105,22 +105,6 @@ class NativeSandboxEnvironment(MacroFuzzEnvironment):
 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 jinja2.nativetypes.native_concat(
-                self.root_render_func(self.new_context(vars)),
-                preserve_quotes=True
-            )
-        except Exception:
-            return self.environment.handle_exception()
-
 
 NativeSandboxEnvironment.template_class = NativeSandboxTemplate  # type: ignore
 
@@ -441,6 +425,18 @@ def render_template(template, ctx: Dict[str, Any], node=None) -> str:
         return template.render(ctx)
 
 
+def _requote_result(raw_value, rendered):
+    double_quoted = raw_value.startswith('"') and raw_value.endswith('"')
+    single_quoted = raw_value.startswith("'") and raw_value.endswith("'")
+    if double_quoted:
+        quote_char = '"'
+    elif single_quoted:
+        quote_char = "'"
+    else:
+        quote_char = ''
+    return f'{quote_char}{rendered}{quote_char}'
+
+
 def get_rendered(
     string: str,
     ctx: Dict[str, Any],
@@ -456,7 +452,11 @@ def get_rendered(
         native=native,
     )
 
-    return render_template(template, ctx, node)
+    result = render_template(template, ctx, node)
+
+    if native and isinstance(result, str):
+        result = _requote_result(string, result)
+    return result
 
 
 def undefined_error(msg) -> NoReturn:
diff --git a/core/dbt/parser/schemas.py b/core/dbt/parser/schemas.py
--- a/core/dbt/parser/schemas.py
+++ b/core/dbt/parser/schemas.py
@@ -196,21 +196,6 @@ def parse_column_tests(
         for test in column.tests:
             self.parse_test(block, test, column)
 
-    def _build_raw_test_keyword_args(
-        self, parsed_node: ParsedSchemaTestNode, builder: TestBuilder
-    ) -> Dict[str, Any]:
-        """Build up the test keyword arguments."""
-        kwargs = parsed_node.test_metadata.kwargs.copy()
-        if isinstance(builder.target, UnparsedNodeUpdate):
-            fmt = "{{{{ ref('{0.name}') }}}}"
-        elif isinstance(builder.target, SourceTarget):
-            fmt = "{{{{ source('{0.source.name}', '{0.table.name}') }}}}"
-        else:
-            raise TypeError(f'invalid target type "{type(builder.target)}"')
-
-        kwargs['model'] = fmt.format(builder.target)
-        return kwargs
-
     def parse_node(self, block: SchemaTestBlock) -> ParsedSchemaTestNode:
         """In schema parsing, we rewrite most of the part of parse_node that
         builds the initial node to be parsed, but rendering is basically the
diff --git a/core/setup.py b/core/setup.py
--- a/core/setup.py
+++ b/core/setup.py
@@ -53,7 +53,7 @@ def read(fname):
         'scripts/dbt',
     ],
     install_requires=[
-        'Jinja2>=2.11,<3',
+        'Jinja2==2.11.2',
         'PyYAML>=3.11',
         'sqlparse>=0.2.3,<0.4',
         'networkx>=2.3,<3',


Test patch:
diff --git a/core/dbt/parser/schema_test_builders.py b/core/dbt/parser/schema_test_builders.py
--- a/core/dbt/parser/schema_test_builders.py
+++ b/core/dbt/parser/schema_test_builders.py
@@ -1,5 +1,6 @@
 import hashlib
 import re
+from copy import deepcopy
 from dataclasses import dataclass
 from typing import (
     Generic, TypeVar, Dict, Any, Tuple, Optional, List, Sequence
@@ -287,6 +288,7 @@ def extract_test_args(test, name=None) -> Tuple[str, Dict[str, Any]]:
                     type(test_name), test_name
                 )
             )
+        test_args = deepcopy(test_args)
         if name is not None:
             test_args['column_name'] = name
         return test_name, test_args