|
3 | 3 | import pytest |
4 | 4 |
|
5 | 5 | from tests.builders import UMFBuilder |
6 | | -from tablespec.authoring.mutations import add_column, modify_column, remove_column, rename_column |
| 6 | +from tablespec.authoring.mutations import ( |
| 7 | + add_column, |
| 8 | + modify_column, |
| 9 | + remove_column, |
| 10 | + remove_expectation, |
| 11 | + rename_column, |
| 12 | +) |
| 13 | +from tablespec.models.umf import UMF, Expectation, ExpectationMeta, ExpectationSuite |
7 | 14 |
|
8 | 15 | pytestmark = [pytest.mark.fast, pytest.mark.no_spark] |
9 | 16 |
|
@@ -89,3 +96,59 @@ def test_original_unchanged(self): |
89 | 96 | result = modify_column(umf, "id", description="Primary key") |
90 | 97 | assert umf.columns[0].description is None |
91 | 98 | assert result.columns[0].description == "Primary key" |
| 99 | + |
| 100 | + |
| 101 | +class TestRemoveExpectation: |
| 102 | + @staticmethod |
| 103 | + def _umf_with_suite() -> UMF: |
| 104 | + umf = UMFBuilder("t").column("id", "INTEGER").column("amount", "DECIMAL").build() |
| 105 | + suite = ExpectationSuite( |
| 106 | + expectations=[ |
| 107 | + Expectation( |
| 108 | + type="expect_column_values_to_not_be_null", |
| 109 | + kwargs={"column": "id"}, |
| 110 | + meta=ExpectationMeta(stage="raw", severity="critical"), |
| 111 | + ), |
| 112 | + Expectation( |
| 113 | + type="expect_column_values_to_be_between", |
| 114 | + kwargs={"column": "amount", "min_value": 0}, |
| 115 | + meta=ExpectationMeta(stage="ingested", severity="warning"), |
| 116 | + ), |
| 117 | + Expectation( |
| 118 | + type="expect_column_values_to_not_be_null", |
| 119 | + kwargs={"column": "amount"}, |
| 120 | + meta=ExpectationMeta(stage="raw", severity="critical"), |
| 121 | + ), |
| 122 | + ], |
| 123 | + ) |
| 124 | + return umf.model_copy(update={"expectations": suite}) |
| 125 | + |
| 126 | + def test_removes_matching_type_and_column(self): |
| 127 | + umf = self._umf_with_suite() |
| 128 | + result, count = remove_expectation(umf, "expect_column_values_to_not_be_null", "id") |
| 129 | + assert count == 1 |
| 130 | + assert len(result.expectations.expectations) == 2 |
| 131 | + |
| 132 | + def test_removes_all_matching_type(self): |
| 133 | + umf = self._umf_with_suite() |
| 134 | + result, count = remove_expectation(umf, "expect_column_values_to_not_be_null") |
| 135 | + assert count == 2 |
| 136 | + assert len(result.expectations.expectations) == 1 |
| 137 | + assert result.expectations.expectations[0].type == "expect_column_values_to_be_between" |
| 138 | + |
| 139 | + def test_no_match_returns_original(self): |
| 140 | + umf = self._umf_with_suite() |
| 141 | + result, count = remove_expectation(umf, "expect_column_to_exist") |
| 142 | + assert count == 0 |
| 143 | + assert result is umf |
| 144 | + |
| 145 | + def test_updates_only_expectations_field(self): |
| 146 | + """Verify remove_expectation mutates only umf.expectations, not legacy fields.""" |
| 147 | + umf = self._umf_with_suite() |
| 148 | + result, count = remove_expectation(umf, "expect_column_values_to_be_between") |
| 149 | + assert count == 1 |
| 150 | + # expectations field is updated |
| 151 | + assert len(result.expectations.expectations) == 2 |
| 152 | + # legacy fields are untouched (None on the builder-produced UMF) |
| 153 | + assert result.quality_checks is None |
| 154 | + assert result.validation_rules is None |
0 commit comments