From 87b48f3e33686d6f777fc52990d270f1e9f8fec8 Mon Sep 17 00:00:00 2001 From: Gerda Shank Date: Fri, 28 Jun 2024 09:43:55 -0400 Subject: [PATCH] [Backport 1.8.latest] Limit data test deprecation warning to root_project (#10375) --- .../unreleased/Fixes-20240627-154448.yaml | 6 ++++ core/dbt/contracts/graph/nodes.py | 25 ++++++------- core/dbt/parser/schemas.py | 27 ++++++++------ core/dbt/parser/sources.py | 2 ++ .../dependencies/test_local_dependency.py | 36 ++++++++++++++++++- 5 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 .changes/unreleased/Fixes-20240627-154448.yaml diff --git a/.changes/unreleased/Fixes-20240627-154448.yaml b/.changes/unreleased/Fixes-20240627-154448.yaml new file mode 100644 index 00000000000..f2ea7dd739c --- /dev/null +++ b/.changes/unreleased/Fixes-20240627-154448.yaml @@ -0,0 +1,6 @@ +kind: Fixes +body: Limit data_tests deprecation to root_project +time: 2024-06-27T15:44:48.579869-04:00 +custom: + Author: gshank + Issue: "9835" diff --git a/core/dbt/contracts/graph/nodes.py b/core/dbt/contracts/graph/nodes.py index 318681371b9..9f6b2431510 100644 --- a/core/dbt/contracts/graph/nodes.py +++ b/core/dbt/contracts/graph/nodes.py @@ -1096,7 +1096,7 @@ def get_full_source_name(self): def get_source_representation(self): return f'source("{self.source.name}", "{self.table.name}")' - def validate_data_tests(self): + def validate_data_tests(self, is_root_project: bool): """ sources parse tests differently than models, so we need to do some validation here where it's done in the PatchParser for other nodes @@ -1107,11 +1107,12 @@ def validate_data_tests(self): "Invalid test config: cannot have both 'tests' and 'data_tests' defined" ) if self.tests: - deprecations.warn( - "project-test-config", - deprecated_path="tests", - exp_path="data_tests", - ) + if is_root_project: + deprecations.warn( + "project-test-config", + deprecated_path="tests", + exp_path="data_tests", + ) self.data_tests.extend(self.tests) self.tests.clear() @@ -1122,11 +1123,12 @@ def validate_data_tests(self): "Invalid test config: cannot have both 'tests' and 'data_tests' defined" ) if column.tests: - deprecations.warn( - "project-test-config", - deprecated_path="tests", - exp_path="data_tests", - ) + if is_root_project: + deprecations.warn( + "project-test-config", + deprecated_path="tests", + exp_path="data_tests", + ) column.data_tests.extend(column.tests) column.tests.clear() @@ -1144,7 +1146,6 @@ def columns(self) -> Sequence[UnparsedColumn]: return [] if self.table.columns is None else self.table.columns def get_tests(self) -> Iterator[Tuple[Dict[str, Any], Optional[UnparsedColumn]]]: - self.validate_data_tests() for data_test in self.data_tests: yield normalize_test(data_test), None diff --git a/core/dbt/parser/schemas.py b/core/dbt/parser/schemas.py index 68fafba85f5..1766a4f71cf 100644 --- a/core/dbt/parser/schemas.py +++ b/core/dbt/parser/schemas.py @@ -542,37 +542,44 @@ def normalize_contract_attribute(self, data, path): def normalize_access_attribute(self, data, path): return self.normalize_attribute(data, path, "access") + @property + def is_root_project(self): + if self.root_project.project_name == self.project.project_name: + return True + return False + def validate_data_tests(self, data): # Rename 'tests' -> 'data_tests' at both model-level and column-level # Raise a validation error if the user has defined both names - def validate_and_rename(data): + def validate_and_rename(data, is_root_project: bool): if data.get("tests"): if "tests" in data and "data_tests" in data: raise ValidationError( "Invalid test config: cannot have both 'tests' and 'data_tests' defined" ) - deprecations.warn( - "project-test-config", - deprecated_path="tests", - exp_path="data_tests", - ) + if is_root_project: + deprecations.warn( + "project-test-config", + deprecated_path="tests", + exp_path="data_tests", + ) data["data_tests"] = data.pop("tests") # model-level tests - validate_and_rename(data) + validate_and_rename(data, self.is_root_project) # column-level tests if data.get("columns"): for column in data["columns"]: - validate_and_rename(column) + validate_and_rename(column, self.is_root_project) # versioned models if data.get("versions"): for version in data["versions"]: - validate_and_rename(version) + validate_and_rename(version, self.is_root_project) if version.get("columns"): for column in version["columns"]: - validate_and_rename(column) + validate_and_rename(column, self.is_root_project) def patch_node_config(self, node, patch): if "access" in patch.config: diff --git a/core/dbt/parser/sources.py b/core/dbt/parser/sources.py index f94262aac03..6ed0cf8a3c9 100644 --- a/core/dbt/parser/sources.py +++ b/core/dbt/parser/sources.py @@ -232,6 +232,8 @@ def get_generic_test_parser_for(self, package_name: str) -> "SchemaGenericTestPa return generic_test_parser def get_source_tests(self, target: UnpatchedSourceDefinition) -> Iterable[GenericTestNode]: + is_root_project = True if self.root_project.project_name == target.package_name else False + target.validate_data_tests(is_root_project) for data_test, column in target.get_tests(): yield self.parse_source_test( target=target, diff --git a/tests/functional/dependencies/test_local_dependency.py b/tests/functional/dependencies/test_local_dependency.py index 04391e0c872..595d1de6be3 100644 --- a/tests/functional/dependencies/test_local_dependency.py +++ b/tests/functional/dependencies/test_local_dependency.py @@ -9,12 +9,13 @@ from pathlib import Path from unittest import mock +from dbt import deprecations import dbt_common.semver as semver import dbt_common.exceptions import dbt.config import dbt.exceptions -from dbt.tests.util import check_relations_equal, run_dbt, run_dbt_and_capture +from dbt.tests.util import check_relations_equal, run_dbt, run_dbt_and_capture, write_file from tests.functional.utils import up_one models__dep_source = """ @@ -353,3 +354,36 @@ def test_local_dependency_same_name_sneaky(self, prepare_dependencies, project): # needed to avoid compilation errors from duplicate package names in test autocleanup run_dbt(["clean"]) + + +source_with_tests = """ +sources: + - name: my_source + schema: invalid_schema + tables: + - name: my_table + - name: seed_source + schema: "{{ var('schema_override', target.schema) }}" + tables: + - name: "seed" + identifier: "seed_subpackage_generate_alias_name" + columns: + - name: id + tests: + - unique + - not_null +""" + + +class TestDependencyTestsConfig(BaseDependencyTest): + def test_dependency_tests_config(self, project): + run_dbt(["deps"]) + # Write a file to local_dependency with a "tests" config + write_file( + source_with_tests, project.project_root, "local_dependency", "models", "schema.yml" + ) + run_dbt(["parse"]) + # Check that project-test-config is NOT in active deprecations, since "tests" is only + # in a dependent project. + expected = set() + assert expected == deprecations.active_deprecations