Skip to content

Commit

Permalink
Refactor normalize_warn_error_options
Browse files Browse the repository at this point in the history
  • Loading branch information
gshank committed Jul 17, 2024
1 parent 7310b79 commit 0baf0c8
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 27 deletions.
59 changes: 33 additions & 26 deletions core/dbt/config/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Dict
from typing import Any, Dict, Optional

from dbt.clients import yaml_helper
from dbt.events.types import InvalidOptionYAML
Expand All @@ -24,36 +24,43 @@ def parse_cli_yaml_string(var_string: str, cli_option_name: str) -> Dict[str, An
raise


def normalize_warn_error_options(
dictionary: Dict[str, Any],
def exclusive_primary_alt_value_setting(
dictionary: Optional[Dict[str, Any]],
primary: str,
alt: str,
parent_config: Optional[str] = None,
) -> None:
"""Fixes fields for warn_error_options from yaml format to fields
expected by the WarnErrorOptions class.
'error' => 'include', 'warn' => 'exclude'
"""Munges in place under the primary the options for the primary and alt values
Also validates that two different forms of accepted keys are not
both provided.
Sometimes we allow setting something via TWO keys, but not at the same time. If both the primary
key and alt key have values, an error gets raised. If the alt key has values, then we update
the dictionary to ensure the primary key contains the values. If neither are set, nothing happens.
"""

if "include" in dictionary and "error" in dictionary:
raise DbtExclusivePropertyUseError(
"Only `error` or `include` can be specified in `warn_error_options`, not both"
)
if dictionary is None:
return

primary_options = dictionary.get(primary)
alt_options = dictionary.get(alt)

if "warn" in dictionary and "exclude" in dictionary:
if primary_options and alt_options:
where = f" in `{parent_config}`" if parent_config is not None else ""
raise DbtExclusivePropertyUseError(
"Only `warn` or `exclude` can be specified in `warn_error_options`, not both"
f"Only `{alt}` or `{primary}` can be specified{where}, not both"
)

convert = {
"error": "include",
"warn": "exclude",
}
for key in list(convert.keys()):
if key in dictionary:
value = dictionary.pop(key)
if value is None:
value = []
dictionary[convert[key]] = value
if "silence" in dictionary and dictionary["silence"] is None:
dictionary["silence"] = []
if alt in dictionary:
alt_value = dictionary.pop(alt)
dictionary[primary] = alt_value


def normalize_warn_error_options(warn_error_options: Dict[str, Any]) -> None:
exclusive_primary_alt_value_setting(
warn_error_options, "include", "error", "warn_error_options"
)
exclusive_primary_alt_value_setting(
warn_error_options, "exclude", "warn", "warn_error_options"
)
for key in ("include", "exclude", "silence"):
if key in warn_error_options and warn_error_options[key] is None:
warn_error_options[key] = []
41 changes: 40 additions & 1 deletion tests/unit/config/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,48 @@
import pytest

from dbt.config.utils import normalize_warn_error_options
from dbt.config.utils import (
exclusive_primary_alt_value_setting,
normalize_warn_error_options,
)
from dbt.exceptions import DbtExclusivePropertyUseError


class TestExclusivePrimaryAltValueSetting:
@pytest.fixture(scope="class")
def primary_key(self) -> str:
return "key_a"

@pytest.fixture(scope="class")
def alt_key(self) -> str:
return "key_b"

@pytest.fixture(scope="class")
def value(self) -> str:
return "I LIKE CATS"

def test_primary_set(self, primary_key: str, alt_key: str, value: str):
test_dict = {primary_key: value}
exclusive_primary_alt_value_setting(test_dict, primary_key, alt_key)
assert test_dict.get(primary_key) == value
assert test_dict.get(alt_key) is None

def test_alt_set(self, primary_key: str, alt_key: str, value: str):
test_dict = {alt_key: value}
exclusive_primary_alt_value_setting(test_dict, primary_key, alt_key)
assert test_dict.get(primary_key) == value

def test_primary_and_alt_set(self, primary_key: str, alt_key: str, value: str):
test_dict = {primary_key: value, alt_key: value}
with pytest.raises(DbtExclusivePropertyUseError):
exclusive_primary_alt_value_setting(test_dict, primary_key, alt_key)

def test_neither_primary_nor_alt_set(self, primary_key: str, alt_key: str):
test_dict = {}
exclusive_primary_alt_value_setting(test_dict, primary_key, alt_key)
assert test_dict.get(primary_key) is None
assert test_dict.get(alt_key) is None


class TestNormalizeWarnErrorOptions:
def test_primary_set(self):
test_dict = {
Expand Down

0 comments on commit 0baf0c8

Please sign in to comment.