datahub/metadata-ingestion/tests/unit/config/test_pydantic_validators.py

135 lines
4.1 KiB
Python

from typing import Optional
import pydantic
import pytest
from pydantic import ValidationError
from datahub.configuration.common import ConfigModel, ConfigurationWarning
from datahub.configuration.validate_field_deprecation import pydantic_field_deprecated
from datahub.configuration.validate_field_removal import pydantic_removed_field
from datahub.configuration.validate_field_rename import pydantic_renamed_field
from datahub.configuration.validate_multiline_string import pydantic_multiline_string
from datahub.utilities.global_warning_util import (
clear_global_warnings,
get_global_warnings,
)
def test_field_rename():
class TestModel(ConfigModel):
b: str
_validate_rename = pydantic_renamed_field("a", "b")
v = TestModel.parse_obj({"b": "original"})
assert v.b == "original"
with pytest.warns(ConfigurationWarning, match="a is deprecated"):
v = TestModel.parse_obj({"a": "renamed"})
assert v.b == "renamed"
with pytest.raises(ValidationError):
TestModel.parse_obj({"a": "foo", "b": "bar"})
with pytest.raises(ValidationError):
TestModel.parse_obj({})
def test_field_multiple_fields_rename():
class TestModel(ConfigModel):
b: str
b1: str
_validate_deprecated = pydantic_renamed_field("a", "b")
_validate_deprecated1 = pydantic_renamed_field("a1", "b1")
v = TestModel.parse_obj({"b": "original", "b1": "original"})
assert v.b == "original"
assert v.b1 == "original"
with pytest.warns(ConfigurationWarning, match=r"a.* is deprecated"):
v = TestModel.parse_obj({"a": "renamed", "a1": "renamed"})
assert v.b == "renamed"
assert v.b1 == "renamed"
with pytest.raises(ValidationError):
TestModel.parse_obj({"a": "foo", "b": "bar", "b1": "ok"})
with pytest.raises(ValidationError):
TestModel.parse_obj({"a1": "foo", "b1": "bar", "b": "ok"})
with pytest.raises(ValidationError):
TestModel.parse_obj({"b": "foo"})
with pytest.raises(ValidationError):
TestModel.parse_obj({"b1": "foo"})
with pytest.raises(ValidationError):
TestModel.parse_obj({})
def test_field_remove():
class TestModel(ConfigModel):
b: str
_validate_removed_r1 = pydantic_removed_field("r1")
_validate_removed_r2 = pydantic_removed_field("r2")
v = TestModel.parse_obj({"b": "original"})
assert v.b == "original"
with pytest.warns(ConfigurationWarning, match=r"r\d was removed"):
v = TestModel.parse_obj({"b": "original", "r1": "removed", "r2": "removed"})
assert v.b == "original"
def test_field_deprecated():
clear_global_warnings()
class TestModel(ConfigModel):
d1: Optional[str] = None
d2: Optional[str] = None
b: str
_validate_deprecated_d1 = pydantic_field_deprecated("d1")
_validate_deprecated_d2 = pydantic_field_deprecated("d2")
v = TestModel.parse_obj({"b": "original"})
assert v.b == "original"
with pytest.warns(ConfigurationWarning, match=r"d\d.+ deprecated"):
v = TestModel.parse_obj(
{"b": "original", "d1": "deprecated", "d2": "deprecated"}
)
assert v.b == "original"
assert v.d1 == "deprecated"
assert v.d2 == "deprecated"
assert any(["d1 is deprecated" in warning for warning in get_global_warnings()])
assert any(["d2 is deprecated" in warning for warning in get_global_warnings()])
clear_global_warnings()
def test_multiline_string_fixer():
class TestModel(ConfigModel):
s: str
m: Optional[pydantic.SecretStr] = None
_validate_s = pydantic_multiline_string("s")
_validate_m = pydantic_multiline_string("m")
v = TestModel.parse_obj({"s": "foo\nbar"})
assert v.s == "foo\nbar"
v = TestModel.parse_obj({"s": "foo\\nbar"})
assert v.s == "foo\nbar"
v = TestModel.parse_obj({"s": "normal", "m": "foo\\nbar"})
assert v.s == "normal"
assert v.m
assert v.m.get_secret_value() == "foo\nbar"
v = TestModel.parse_obj({"s": "normal", "m": pydantic.SecretStr("foo\\nbar")})
assert v.m
assert v.m.get_secret_value() == "foo\nbar"