mirror of
https://github.com/dbt-labs/dbt-core
synced 2025-12-20 13:41:27 +00:00
Compare commits
5 Commits
enable-pos
...
qmalcolm--
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19a5a62ebb | ||
|
|
aa15c2d607 | ||
|
|
739b48c786 | ||
|
|
6739349836 | ||
|
|
444aa9042c |
@@ -3,7 +3,7 @@ import os
|
||||
import re
|
||||
from datetime import date, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterator
|
||||
from typing import Any, Dict, Iterator, List
|
||||
|
||||
import jsonschema
|
||||
from jsonschema import ValidationError
|
||||
@@ -57,6 +57,11 @@ def error_path_to_string(error: jsonschema.ValidationError) -> str:
|
||||
return path
|
||||
|
||||
|
||||
def _additional_properties_violation_keys(error: ValidationError) -> List[str]:
|
||||
found_keys = re.findall(r"'\S+'", error.message)
|
||||
return [key.strip("'") for key in found_keys]
|
||||
|
||||
|
||||
def jsonschema_validate(schema: Dict[str, Any], json: Dict[str, Any], file_path: str) -> None:
|
||||
|
||||
if not os.environ.get("DBT_ENV_PRIVATE_RUN_JSONSCHEMA_VALIDATIONS"):
|
||||
@@ -69,20 +74,23 @@ def jsonschema_validate(schema: Dict[str, Any], json: Dict[str, Any], file_path:
|
||||
# Listify the error path to make it easier to work with (it's a deque in the ValidationError object)
|
||||
error_path = list(error.path)
|
||||
if error.validator == "additionalProperties":
|
||||
key = re.search(r"'\S+'", error.message)
|
||||
keys = _additional_properties_violation_keys(error)
|
||||
if len(error.path) == 0:
|
||||
deprecations.warn(
|
||||
"custom-top-level-key-deprecation",
|
||||
msg="Unexpected top-level key" + (" " + key.group() if key else ""),
|
||||
file=file_path,
|
||||
)
|
||||
for key in keys:
|
||||
deprecations.warn(
|
||||
"custom-top-level-key-deprecation",
|
||||
msg="Unexpected top-level key" + (" " + key if key else ""),
|
||||
file=file_path,
|
||||
)
|
||||
else:
|
||||
deprecations.warn(
|
||||
"custom-key-in-object-deprecation",
|
||||
key=key.group() if key else "",
|
||||
file=file_path,
|
||||
key_path=error_path_to_string(error),
|
||||
)
|
||||
key_path = error_path_to_string(error)
|
||||
for key in keys:
|
||||
deprecations.warn(
|
||||
"custom-key-in-object-deprecation",
|
||||
key=key,
|
||||
file=file_path,
|
||||
key_path=key_path,
|
||||
)
|
||||
elif (
|
||||
error.validator == "anyOf"
|
||||
and len(error_path) > 0
|
||||
@@ -90,12 +98,20 @@ def jsonschema_validate(schema: Dict[str, Any], json: Dict[str, Any], file_path:
|
||||
and isinstance(error.instance, dict)
|
||||
and len(error.instance.keys()) > 0
|
||||
):
|
||||
deprecations.warn(
|
||||
"custom-key-in-config-deprecation",
|
||||
key=(list(error.instance.keys()))[0],
|
||||
file=file_path,
|
||||
key_path=error_path_to_string(error),
|
||||
)
|
||||
for sub_error in error.context or []:
|
||||
if (
|
||||
isinstance(sub_error, ValidationError)
|
||||
and sub_error.validator == "additionalProperties"
|
||||
):
|
||||
keys = _additional_properties_violation_keys(sub_error)
|
||||
key_path = error_path_to_string(error)
|
||||
for key in keys:
|
||||
deprecations.warn(
|
||||
"custom-key-in-config-deprecation",
|
||||
key=key,
|
||||
file=file_path,
|
||||
key_path=key_path,
|
||||
)
|
||||
else:
|
||||
deprecations.warn(
|
||||
"generic-json-schema-validation-deprecation",
|
||||
|
||||
@@ -168,6 +168,16 @@ models:
|
||||
my_custom_key: "my_custom_value"
|
||||
"""
|
||||
|
||||
multiple_custom_keys_in_config_yaml = """
|
||||
models:
|
||||
- name: models_trivial
|
||||
description: "This is a test model"
|
||||
deprecation_date: 1999-01-01 00:00:00.00+00:00
|
||||
config:
|
||||
my_custom_key: "my_custom_value"
|
||||
my_custom_key2: "my_custom_value2"
|
||||
"""
|
||||
|
||||
custom_key_in_object_yaml = """
|
||||
models:
|
||||
- name: models_trivial
|
||||
|
||||
@@ -26,6 +26,7 @@ from tests.functional.deprecations.fixtures import (
|
||||
duplicate_keys_yaml,
|
||||
invalid_deprecation_date_yaml,
|
||||
models_trivial__model_sql,
|
||||
multiple_custom_keys_in_config_yaml,
|
||||
)
|
||||
from tests.utils import EventCatcher
|
||||
|
||||
@@ -341,7 +342,10 @@ class TestCustomKeyInConfigDeprecation:
|
||||
@mock.patch.dict(os.environ, {"DBT_ENV_PRIVATE_RUN_JSONSCHEMA_VALIDATIONS": "True"})
|
||||
def test_duplicate_yaml_keys_in_schema_files(self, project):
|
||||
event_catcher = EventCatcher(CustomKeyInConfigDeprecation)
|
||||
run_dbt(["parse", "--no-partial-parse"], callbacks=[event_catcher.catch])
|
||||
run_dbt(
|
||||
["parse", "--no-partial-parse", "--show-all-deprecations"],
|
||||
callbacks=[event_catcher.catch],
|
||||
)
|
||||
assert len(event_catcher.caught_events) == 1
|
||||
assert (
|
||||
"Custom key `my_custom_key` found in `config` at path `models[0].config`"
|
||||
@@ -349,6 +353,32 @@ class TestCustomKeyInConfigDeprecation:
|
||||
)
|
||||
|
||||
|
||||
class TestMultipleCustomKeysInConfigDeprecation:
|
||||
@pytest.fixture(scope="class")
|
||||
def models(self):
|
||||
return {
|
||||
"models_trivial.sql": models_trivial__model_sql,
|
||||
"models.yml": multiple_custom_keys_in_config_yaml,
|
||||
}
|
||||
|
||||
@mock.patch.dict(os.environ, {"DBT_ENV_PRIVATE_RUN_JSONSCHEMA_VALIDATIONS": "True"})
|
||||
def test_duplicate_yaml_keys_in_schema_files(self, project):
|
||||
event_catcher = EventCatcher(CustomKeyInConfigDeprecation)
|
||||
run_dbt(
|
||||
["parse", "--no-partial-parse", "--show-all-deprecations"],
|
||||
callbacks=[event_catcher.catch],
|
||||
)
|
||||
assert len(event_catcher.caught_events) == 2
|
||||
assert (
|
||||
"Custom key `my_custom_key` found in `config` at path `models[0].config`"
|
||||
in event_catcher.caught_events[0].info.msg
|
||||
)
|
||||
assert (
|
||||
"Custom key `my_custom_key2` found in `config` at path `models[0].config`"
|
||||
in event_catcher.caught_events[1].info.msg
|
||||
)
|
||||
|
||||
|
||||
class TestCustomKeyInObjectDeprecation:
|
||||
@pytest.fixture(scope="class")
|
||||
def models(self):
|
||||
@@ -363,7 +393,7 @@ class TestCustomKeyInObjectDeprecation:
|
||||
run_dbt(["parse", "--no-partial-parse"], callbacks=[event_catcher.catch])
|
||||
assert len(event_catcher.caught_events) == 1
|
||||
assert (
|
||||
"Custom key `'my_custom_property'` found at `models[0]` in file"
|
||||
"Custom key `my_custom_property` found at `models[0]` in file"
|
||||
in event_catcher.caught_events[0].info.msg
|
||||
)
|
||||
|
||||
@@ -380,3 +410,25 @@ class TestJsonschemaValidationDeprecationsArentRunWithoutEnvVar:
|
||||
event_catcher = EventCatcher(CustomKeyInObjectDeprecation)
|
||||
run_dbt(["parse", "--no-partial-parse"], callbacks=[event_catcher.catch])
|
||||
assert len(event_catcher.caught_events) == 0
|
||||
|
||||
|
||||
class TestHappyPathProjectHasNoDeprecations:
|
||||
@mock.patch.dict(os.environ, {"DBT_ENV_PRIVATE_RUN_JSONSCHEMA_VALIDATIONS": "True"})
|
||||
def test_happy_path_project_has_no_deprecations(self, happy_path_project):
|
||||
event_cathcer = EventCatcher(DeprecationsSummary)
|
||||
run_dbt(
|
||||
["parse", "--no-partial-parse", "--show-all-deprecations"],
|
||||
callbacks=[event_cathcer.catch],
|
||||
)
|
||||
assert len(event_cathcer.caught_events) == 0
|
||||
|
||||
|
||||
class TestBaseProjectHasNoDeprecations:
|
||||
@mock.patch.dict(os.environ, {"DBT_ENV_PRIVATE_RUN_JSONSCHEMA_VALIDATIONS": "True"})
|
||||
def test_base_project_has_no_deprecations(self, project):
|
||||
event_cathcer = EventCatcher(DeprecationsSummary)
|
||||
run_dbt(
|
||||
["parse", "--no-partial-parse", "--show-all-deprecations"],
|
||||
callbacks=[event_cathcer.catch],
|
||||
)
|
||||
assert len(event_cathcer.caught_events) == 0
|
||||
|
||||
@@ -8,8 +8,19 @@ models:
|
||||
data_tests:
|
||||
- unique
|
||||
- not_null
|
||||
config:
|
||||
materialized: table
|
||||
sql_header: "SELECT 1 as header;"
|
||||
on_configuration_change: apply
|
||||
unique_key: id
|
||||
batch_size: day
|
||||
begin: "2020-01-01"
|
||||
lookback: 5
|
||||
concurrent_batches: false
|
||||
- name: metricflow_time_spine
|
||||
description: Day time spine
|
||||
time_spine:
|
||||
standard_granularity_column: date_day
|
||||
columns:
|
||||
- name: date_day
|
||||
granularity: day
|
||||
|
||||
Reference in New Issue
Block a user