-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from joocer/1.5.0
1.5.0
- Loading branch information
Showing
9 changed files
with
272 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
from .internals.expectations import Expectations | ||
from data_expectations.internals.expectations import Expectations | ||
from data_expectations.internals.models import Expectation, ColumnExpectation | ||
|
||
from .internals.evaluate import evaluate_list | ||
from .internals.evaluate import evaluate_record | ||
from data_expectations.internals.evaluate import evaluate_list | ||
from data_expectations.internals.evaluate import evaluate_record |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
import json | ||
from copy import deepcopy | ||
from dataclasses import dataclass | ||
from dataclasses import field | ||
from typing import Any | ||
from typing import Dict | ||
from typing import Type | ||
from typing import Union | ||
|
||
|
||
@dataclass | ||
class Expectation: | ||
""" | ||
Represents a general Data Expectation. | ||
""" | ||
|
||
expectation: str | ||
config: Dict[str, Any] = field(default_factory=dict) | ||
|
||
def to_dict(self) -> Dict[str, Any]: | ||
""" | ||
Converts the Expectation instance to a dictionary representation. | ||
Returns: | ||
A dictionary containing the expectation and its configuration. | ||
""" | ||
return {"expectation": self.expectation, **self.config} | ||
|
||
@classmethod | ||
def load_base(cls: Type["Expectation"], serialized: Union[Dict[str, Any], str]) -> Dict[str, Any]: | ||
""" | ||
Loads a serialized Expectation and returns it as a dictionary. | ||
Parameters: | ||
serialized: Serialized Expectation as a dictionary or JSON string. | ||
Returns: | ||
A dictionary representation of the serialized Expectation. | ||
""" | ||
if isinstance(serialized, str): | ||
serialized = dict(json.loads(serialized)) | ||
serialized_copy: dict = deepcopy(serialized) | ||
if "expectation" not in serialized_copy: | ||
raise ValueError("Missing 'expectation' key in Expectation.") | ||
return serialized_copy | ||
|
||
@classmethod | ||
def load(cls: Type["Expectation"], serialized: Union[Dict[str, Any], str]) -> "Expectation": | ||
""" | ||
Loads a serialized Expectation and returns it as an instance. | ||
Parameters: | ||
serialized: Serialized Expectation as a dictionary or JSON string. | ||
Returns: | ||
An Expectation instance populated with the serialized data. | ||
""" | ||
serialized_copy = cls.load_base(serialized) | ||
expectation = serialized_copy.pop("expectation") | ||
config = serialized_copy | ||
return cls(expectation=expectation, config=config) | ||
|
||
|
||
class ColumnExpectation(Expectation): | ||
""" | ||
Represents a Data Expectation related to a specific column. | ||
""" | ||
|
||
def __init__(self, expectation: str, column: str, config: Dict[str, Any] = None): | ||
""" | ||
Initializes a ColumnExpectation instance. | ||
Parameters: | ||
expectation: The expectation type as a string. | ||
column: The column the expectation applies to. | ||
config: Additional configuration as a dictionary. | ||
""" | ||
super().__init__(expectation, config or {}) | ||
self.column = column | ||
|
||
def to_dict(self) -> Dict[str, Any]: | ||
""" | ||
Converts the ColumnExpectation instance to a dictionary representation. | ||
Returns: | ||
A dictionary containing the expectation, column, and its configuration. | ||
""" | ||
return {"expectation": self.expectation, "column": self.column, **self.config} | ||
|
||
@classmethod | ||
def load(cls: Type["ColumnExpectation"], serialized: Union[Dict[str, Any], str]) -> "ColumnExpectation": | ||
""" | ||
Loads a serialized ColumnExpectation and returns it as an instance. | ||
Parameters: | ||
serialized: Serialized ColumnExpectation as a dictionary or JSON string. | ||
Returns: | ||
A ColumnExpectation instance populated with the serialized data. | ||
""" | ||
serialized_copy = cls.load_base(serialized) | ||
if "column" not in serialized_copy: | ||
raise ValueError("Missing 'column' key in Expectation.") | ||
expectation = serialized_copy.pop("expectation") | ||
column = serialized_copy.pop("column") | ||
config = serialized_copy | ||
return cls(expectation=expectation, column=column, config=config) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import os | ||
import sys | ||
|
||
sys.path.insert(1, os.path.join(sys.path[0], "..")) | ||
|
||
|
||
import json | ||
import pytest | ||
from data_expectations import Expectation, ColumnExpectation | ||
|
||
|
||
def test_expectation_to_dict(): | ||
exp = Expectation("test_expectation", {"some_key": "some_value"}) | ||
assert exp.to_dict() == {"expectation": "test_expectation", "some_key": "some_value"} | ||
|
||
|
||
def test_expectation_load_from_dict(): | ||
serialized = {"expectation": "test_expectation", "some_key": "some_value"} | ||
exp = Expectation.load(serialized) | ||
assert exp.expectation == "test_expectation" | ||
assert exp.config == {"some_key": "some_value"} | ||
|
||
|
||
def test_expectation_load_from_json_str(): | ||
serialized = json.dumps({"expectation": "test_expectation", "some_key": "some_value"}) | ||
exp = Expectation.load(serialized) | ||
assert exp.expectation == "test_expectation" | ||
assert exp.config == {"some_key": "some_value"} | ||
|
||
|
||
def test_expectation_load_missing_key(): | ||
serialized = {"some_key": "some_value"} | ||
with pytest.raises(ValueError): | ||
Expectation.load(serialized) | ||
|
||
|
||
def test_column_expectation_to_dict(): | ||
exp = ColumnExpectation("test_expectation", "test_column", {"some_key": "some_value"}) | ||
assert exp.to_dict() == {"expectation": "test_expectation", "column": "test_column", "some_key": "some_value"} | ||
|
||
|
||
def test_column_expectation_load_from_dict(): | ||
serialized = {"expectation": "test_expectation", "column": "test_column", "some_key": "some_value"} | ||
exp = ColumnExpectation.load(serialized) | ||
assert exp.expectation == "test_expectation" | ||
assert exp.column == "test_column" | ||
assert exp.config == {"some_key": "some_value"} | ||
|
||
|
||
def test_column_expectation_load_from_json_str(): | ||
serialized = json.dumps({"expectation": "test_expectation", "column": "test_column", "some_key": "some_value"}) | ||
exp = ColumnExpectation.load(serialized) | ||
assert exp.expectation == "test_expectation" | ||
assert exp.column == "test_column" | ||
assert exp.config == {"some_key": "some_value"} | ||
|
||
|
||
def test_column_expectation_load_missing_key(): | ||
serialized = {"expectation": "test_expectation", "some_key": "some_value"} | ||
with pytest.raises(ValueError): | ||
ColumnExpectation.load(serialized) | ||
|
||
|
||
if __name__ == "__main__": # pragma: no cover | ||
test_expectation_to_dict() | ||
test_expectation_load_from_dict() | ||
test_expectation_load_from_json_str() | ||
test_expectation_load_missing_key() | ||
|
||
test_column_expectation_to_dict() | ||
test_column_expectation_load_from_dict() | ||
test_column_expectation_load_from_json_str() | ||
test_column_expectation_load_missing_key() | ||
|
||
print("✅ okay") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import os | ||
import sys | ||
import json | ||
|
||
|
||
sys.path.insert(1, os.path.join(sys.path[0], "..")) | ||
|
||
from data_expectations import Expectations, Expectation, ColumnExpectation | ||
|
||
|
||
def test_expectations_initializer(): | ||
# Create expectations as different types | ||
exp1 = Expectation("expect_test", {"key1": "value1"}) | ||
exp2_dict = {"expectation": "expect_test2", "key2": "value2"} | ||
exp2 = Expectation.load(exp2_dict) | ||
exp3_json = json.dumps({"expectation": "expect_test3", "key3": "value3"}) | ||
exp3 = Expectation.load(json.loads(exp3_json)) | ||
|
||
col_exp1 = ColumnExpectation("expect_test_col", "col1", {"key1": "value1"}) | ||
col_exp2_dict = {"expectation": "expect_test_col2", "column": "col2", "key2": "value2"} | ||
col_exp2 = ColumnExpectation.load(col_exp2_dict) | ||
col_exp3_json = json.dumps({"expectation": "expect_test_col3", "column": "col3", "key3": "value3"}) | ||
col_exp3 = ColumnExpectation.load(json.loads(col_exp3_json)) | ||
|
||
# Initialize Expectations class | ||
expectations = Expectations([exp1, exp2_dict, exp3_json, col_exp1, col_exp2_dict, col_exp3_json]) | ||
|
||
# Validate | ||
assert len(expectations.set_of_expectations) == 6 | ||
|
||
assert isinstance(expectations.set_of_expectations[0], Expectation) | ||
assert isinstance(expectations.set_of_expectations[1], Expectation) | ||
assert isinstance(expectations.set_of_expectations[2], Expectation) | ||
assert isinstance(expectations.set_of_expectations[3], ColumnExpectation) | ||
assert isinstance(expectations.set_of_expectations[4], ColumnExpectation) | ||
assert isinstance(expectations.set_of_expectations[5], ColumnExpectation) | ||
|
||
|
||
if __name__ == "__main__": # pragma: no cover | ||
test_expectations_initializer() | ||
|
||
print("✅ okay") |