data-sitter 0.1.6__tar.gz → 0.1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {data_sitter-0.1.6 → data_sitter-0.1.7}/PKG-INFO +1 -1
  2. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/Contract.py +12 -5
  3. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/FieldResolver.py +4 -2
  4. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/field_types/BaseField.py +9 -3
  5. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter.egg-info/PKG-INFO +1 -1
  6. {data_sitter-0.1.6 → data_sitter-0.1.7}/pyproject.toml +1 -1
  7. {data_sitter-0.1.6 → data_sitter-0.1.7}/tests/test_contract.py +17 -8
  8. {data_sitter-0.1.6 → data_sitter-0.1.7}/tests/test_field_resolver.py +2 -2
  9. {data_sitter-0.1.6 → data_sitter-0.1.7}/README.md +0 -0
  10. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/Validation.py +0 -0
  11. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/__init__.py +0 -0
  12. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/cli.py +0 -0
  13. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/field_types/FieldTypes.py +0 -0
  14. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/field_types/FloatField.py +0 -0
  15. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/field_types/IntegerField.py +0 -0
  16. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/field_types/NumericField.py +0 -0
  17. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/field_types/StringField.py +0 -0
  18. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/field_types/__init__.py +0 -0
  19. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/Enums.py +0 -0
  20. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/LogicalRule.py +0 -0
  21. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/MatchedRule.py +0 -0
  22. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/Parser/RuleParser.py +0 -0
  23. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/Parser/__init__.py +0 -0
  24. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/Parser/alias_parameters_parser.py +0 -0
  25. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/Parser/parser_utils.py +0 -0
  26. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/ProcessedRule.py +0 -0
  27. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/Rule.py +0 -0
  28. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/RuleRegistry.py +0 -0
  29. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/rules/__init__.py +0 -0
  30. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/utils/__init__.py +0 -0
  31. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter/utils/logger_config.py +0 -0
  32. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter.egg-info/SOURCES.txt +0 -0
  33. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter.egg-info/dependency_links.txt +0 -0
  34. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter.egg-info/entry_points.txt +0 -0
  35. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter.egg-info/requires.txt +0 -0
  36. {data_sitter-0.1.6 → data_sitter-0.1.7}/data_sitter.egg-info/top_level.txt +0 -0
  37. {data_sitter-0.1.6 → data_sitter-0.1.7}/setup.cfg +0 -0
  38. {data_sitter-0.1.6 → data_sitter-0.1.7}/tests/test_cli.py +0 -0
  39. {data_sitter-0.1.6 → data_sitter-0.1.7}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-sitter
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A Python library that reads data contracts and generates Pydantic models for seamless data validation.
5
5
  Author-email: Lázaro Pereira Candea <lazaro@candea.es>
6
6
  Requires-Python: >=3.8
@@ -22,7 +22,8 @@ class ContractWithoutName(Exception):
22
22
  class Field(NamedTuple):
23
23
  name: str
24
24
  type: str
25
- rules: List[str]
25
+ description: str = None
26
+ rules: List[str] = []
26
27
 
27
28
 
28
29
  class Contract:
@@ -67,7 +68,9 @@ class Contract:
67
68
  field_validators = {}
68
69
  for field in self.fields:
69
70
  field_resolver = self.field_resolvers[field.type]
70
- field_validators[field.name] = field_resolver.get_field_validator(field.name, field.rules)
71
+ field_validators[field.name] = field_resolver.get_field_validator(
72
+ field.name, field.rules, field.description
73
+ )
71
74
  return field_validators
72
75
 
73
76
  @cached_property
@@ -98,6 +101,7 @@ class Contract:
98
101
  {
99
102
  "name": name,
100
103
  "type": field_validator.type_name.value,
104
+ **({"description": field_validator.description} if field_validator.description is not None else {}),
101
105
  "rules": [rule.parsed_rule for rule in self.rules.get(name, [])]
102
106
  }
103
107
  for name, field_validator in self.field_validators.items()
@@ -105,12 +109,15 @@ class Contract:
105
109
  "values": self.rule_parser.values
106
110
  }
107
111
 
108
- def get_json_contract(self, indent: int=2) -> str:
109
- return json.dumps(self.contract, indent=indent)
112
+ def to_json(self, indent: int=2) -> str:
113
+ return json.dumps(self.contract, indent=indent, sort_keys=False)
110
114
 
111
- def get_yaml_contract(self, indent: int=2) -> str:
115
+ def to_yaml(self, indent: int=2) -> str:
112
116
  return yaml.dump(self.contract, Dumper=yaml.Dumper, indent=indent, sort_keys=False)
113
117
 
118
+ def to_json_schema(self) -> dict:
119
+ return self.pydantic_model.model_json_schema()
120
+
114
121
  def get_front_end_contract(self) -> dict:
115
122
  return {
116
123
  "name": self.name,
@@ -25,8 +25,10 @@ class FieldResolver:
25
25
  self.rules = RuleRegistry.get_rules_for(field_class)
26
26
  self._match_rule_cache = {}
27
27
 
28
- def get_field_validator(self, name: str, parsed_rules: List[Union[str, dict]]) -> BaseField:
29
- field_validator = self.field_class(name)
28
+ def get_field_validator(
29
+ self, name: str, parsed_rules: List[Union[str, dict]], description: str = None
30
+ ) -> BaseField:
31
+ field_validator = self.field_class(name, description)
30
32
  processed_rules = self.get_processed_rules(parsed_rules)
31
33
  validators = [pr.get_validator(field_validator) for pr in processed_rules]
32
34
  field_validator.validators = validators
@@ -1,7 +1,7 @@
1
1
  from abc import ABC
2
2
  from typing import Annotated, Callable, List, Optional, Type
3
3
 
4
- from pydantic import AfterValidator
4
+ from pydantic import AfterValidator, Field
5
5
 
6
6
  from .FieldTypes import FieldTypes
7
7
  from ..rules import register_rule, register_field
@@ -23,13 +23,15 @@ def aggregated_validator(validators: List[Callable], is_optional: bool):
23
23
  @register_field
24
24
  class BaseField(ABC):
25
25
  name: str
26
+ description: str
26
27
  is_optional: bool
27
28
  validators = None
28
29
  field_type = None
29
30
  type_name = FieldTypes.BASE
30
31
 
31
- def __init__(self, name: str) -> None:
32
+ def __init__(self, name: str, description: str = None) -> None:
32
33
  self.name = name
34
+ self.description = description
33
35
  self.is_optional = True
34
36
  self.validators = None
35
37
 
@@ -53,7 +55,11 @@ class BaseField(ABC):
53
55
  if self.validators is None:
54
56
  raise NotInitialisedError()
55
57
  field_type = Optional[self.field_type] if self.is_optional else self.field_type
56
- return Annotated[field_type, AfterValidator(aggregated_validator(self.validators, self.is_optional))]
58
+ return Annotated[
59
+ field_type,
60
+ Field(description=self.description),
61
+ AfterValidator(aggregated_validator(self.validators, self.is_optional))
62
+ ]
57
63
 
58
64
  @classmethod
59
65
  def get_parents(cls: Type["BaseField"]) -> List[Type["BaseField"]]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-sitter
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: A Python library that reads data contracts and generates Pydantic models for seamless data validation.
5
5
  Author-email: Lázaro Pereira Candea <lazaro@candea.es>
6
6
  Requires-Python: >=3.8
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = 'data-sitter'
7
- version = "0.1.6"
7
+ version = "0.1.7"
8
8
  description = "A Python library that reads data contracts and generates Pydantic models for seamless data validation."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -13,6 +13,7 @@ def sample_contract_dict():
13
13
  {
14
14
  "name": "name",
15
15
  "type": "String",
16
+ "description": "The name of the person",
16
17
  "rules": [
17
18
  "Is not null",
18
19
  "Has minimum length 3"
@@ -142,19 +143,27 @@ class TestContract:
142
143
  assert "age" in validation.errors
143
144
  assert validation.unknowns == {"extra": "value"}
144
145
 
145
- def test_get_json_contract(self, sample_contract):
146
+ def test_contract_property(self, sample_contract, sample_contract_dict):
147
+ """Test contract property"""
148
+ assert sample_contract.contract == sample_contract_dict
149
+
150
+ def test_to_json(self, sample_contract, sample_contract_dict):
146
151
  """Test JSON contract generation"""
147
- json_contract = sample_contract.get_json_contract()
152
+ json_contract = sample_contract.to_json()
148
153
  contract_dict = json.loads(json_contract)
149
- assert contract_dict["name"] == "TestContract"
150
- assert len(contract_dict["fields"]) == 2
154
+ assert contract_dict == sample_contract_dict
151
155
 
152
- def test_get_yaml_contract(self, sample_contract):
156
+ def test_to_yaml(self, sample_contract, sample_contract_dict):
153
157
  """Test YAML contract generation"""
154
- yaml_contract = sample_contract.get_yaml_contract()
158
+ yaml_contract = sample_contract.to_yaml()
155
159
  contract_dict = yaml.safe_load(yaml_contract)
156
- assert contract_dict["name"] == "TestContract"
157
- assert len(contract_dict["fields"]) == 2
160
+ assert contract_dict == sample_contract_dict
161
+
162
+ def test_to_json_schema(self, sample_contract):
163
+ """Test JSON schema generation"""
164
+ json_schema = sample_contract.to_json_schema()
165
+ assert json_schema["title"] == "TestContract"
166
+ assert len(json_schema["properties"]) == 2
158
167
 
159
168
  def test_get_front_end_contract(self, sample_contract):
160
169
  """Test front-end contract representation"""
@@ -59,11 +59,11 @@ class TestFieldResolver:
59
59
 
60
60
  with patch.object(field_resolver, 'get_processed_rules', return_value=[mock_processed_rule]):
61
61
  # Call the method
62
- result = field_resolver.get_field_validator("test_field", ["rule1", "rule2"])
62
+ result = field_resolver.get_field_validator("test_field", ["rule1", "rule2"], "test_description")
63
63
 
64
64
  # Assertions
65
65
  assert result == mock_field_instance
66
- mock_field_class.assert_called_once_with("test_field")
66
+ mock_field_class.assert_called_once_with("test_field", "test_description")
67
67
  mock_processed_rule.get_validator.assert_called_once_with(mock_field_instance)
68
68
  assert mock_field_instance.validators == [mock_validator]
69
69
 
File without changes
File without changes