Skip to content

Commit 2811bc9

Browse files
committed
Update test validator, and update validator, added instances.py, and small fixes on other files
1 parent 3534735 commit 2811bc9

File tree

7 files changed

+459
-360
lines changed

7 files changed

+459
-360
lines changed

sqlalchemyseed/_future/seeder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def _setup_instance(self, class_, kwargs: dict, parent: Entity):
155155

156156
class HybridSeeder:
157157
__model_key = validator.Key.model()
158-
__source_keys = validator.Key.source_keys()
158+
__source_keys = [validator.Key.data(), validator.Key.filter()]
159159

160160
def __init__(self, session: sqlalchemy.orm.Session, ref_prefix):
161161
self.session = session

sqlalchemyseed/errors.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
11
class ClassNotFoundError(Exception):
22
"""Raised when the class is not found"""
33
pass
4+
5+
6+
class MissingRequiredKeyError(Exception):
7+
"""Raised when a required key is missing"""
8+
pass
9+
10+
11+
class MaxLengthExceededError(Exception):
12+
"""Raised when maximum length of data exceeded"""
13+
14+
15+
class InvalidDataTypeError(Exception):
16+
"""Raised when a type of data is not accepted"""
17+
18+
19+
class EmptyDataError(Exception):
20+
"""Raised when data is empty"""

sqlalchemyseed/validator.py

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@
2222
SOFTWARE.
2323
"""
2424

25+
from . import errors
26+
2527

2628
class Key:
2729
def __init__(self, label: str, type_):
2830
self.label = label
2931
self.type = type_
3032

31-
def unpack(self):
32-
return self.label, self.type
33+
# def unpack(self):
34+
# return self.label, self.type
3335

3436
@classmethod
3537
def model(cls):
@@ -46,21 +48,8 @@ def filter(cls):
4648
def is_valid_type(self, entity):
4749
return isinstance(entity, self.type)
4850

49-
@classmethod
50-
def source_keys(cls):
51-
"""The possible pairs of model key [data, filter]
52-
53-
Returns:
54-
list: list of keys object
55-
"""
56-
return [cls.data(), cls.filter()]
57-
58-
@classmethod
59-
def source_keys_labels(cls) -> list:
60-
return [source_key.label for source_key in cls.source_keys()]
61-
62-
def __repr__(self):
63-
return "<{}(label='{}', type='{}')>".format(self.__class__.__name__, self.label, self.type)
51+
def __str__(self):
52+
return self.label
6453

6554
def __eq__(self, o: object) -> bool:
6655
if isinstance(o, self.__class__):
@@ -75,57 +64,81 @@ def __hash__(self):
7564
return hash(self.label)
7665

7766

78-
def validate_key(key: Key, entity: dict):
79-
if key.label not in entity:
80-
raise KeyError("Key {} not found".format(key.label))
81-
if not isinstance(entity[key.label], key.type):
82-
raise TypeError("Invalid type, entity['{}'] type is not '{}'".format(key.label, key.type))
67+
def check_model_key(entity: dict, entity_is_parent: bool):
68+
model = Key.model()
69+
if model not in entity and entity_is_parent:
70+
raise errors.MissingRequiredKeyError("'model' key is missing.")
71+
# check type
72+
if model in entity and not model.is_valid_type(entity[model]):
73+
raise errors.InvalidDataTypeError("'model' data should be 'string'.")
74+
75+
76+
def check_max_length(entity: dict):
77+
if len(entity) > 2:
78+
raise errors.MaxLengthExceededError("Length should not exceed by 2.")
79+
80+
81+
def check_source_key(entity: dict, source_keys: list[Key]) -> Key:
82+
source_key: Key = next(
83+
(sk for sk in source_keys if sk in entity),
84+
None
85+
)
86+
87+
# check if current keys has at least, data or filter key
88+
if source_key is None:
89+
raise errors.MissingRequiredKeyError("Missing 'data' or 'filter' key.")
90+
91+
return source_key
92+
93+
94+
def check_source_data(source_data, source_key: Key):
95+
if not isinstance(source_data, dict) and not isinstance(source_data, list):
96+
raise errors.InvalidDataTypeError(f"Invalid type, {str(source_key)} should be either 'dict' or 'list'.")
97+
98+
if isinstance(source_data, list) and len(source_data) == 0:
99+
raise errors.EmptyDataError("Empty list, 'data' or 'filter' list should not be empty.")
100+
101+
102+
def iter_reference_relationships(kwargs: dict, ref_prefix):
103+
for attr_name, value in kwargs.items():
104+
if attr_name.startswith(ref_prefix):
105+
# removed prefix
106+
yield attr_name[len(ref_prefix):], value
83107

84108

85109
class SchemaValidator:
86-
__model_key = Key.model()
87-
__source_keys = Key.source_keys()
110+
_source_keys = None
88111

89112
@classmethod
90-
def validate(cls, entities, ref_prefix='!'):
113+
def validate(cls, entities, ref_prefix='!', source_keys=None):
114+
if source_keys is None:
115+
cls._source_keys = [Key.data(), Key.filter()]
91116
cls._pre_validate(entities, is_parent=True, ref_prefix=ref_prefix)
92117

93118
@classmethod
94119
def _pre_validate(cls, entities: dict, is_parent=True, ref_prefix='!'):
120+
if not isinstance(entities, dict) and not isinstance(entities, list):
121+
raise errors.InvalidDataTypeError("Invalid type, should be list or dict")
122+
if len(entities) == 0:
123+
return
95124
if isinstance(entities, dict):
96-
if len(entities) > 0:
97-
return cls._validate(entities, is_parent, ref_prefix)
125+
return cls._validate(entities, is_parent, ref_prefix)
98126
elif isinstance(entities, list):
99127
for entity in entities:
100128
cls._pre_validate(entity, is_parent, ref_prefix)
101-
else:
102-
raise TypeError("Invalid type, should be list or dict")
103129

104130
@classmethod
105-
def _validate(cls, entity: dict, is_parent=True, ref_prefix='!'):
106-
if len(entity) > 2:
107-
raise ValueError("Should not have items for than 2.")
108-
109-
try:
110-
validate_key(cls.__model_key, entity)
111-
except KeyError as error:
112-
if is_parent:
113-
raise error
131+
def _validate(cls, entity: dict, entity_is_parent=True, ref_prefix='!'):
132+
check_max_length(entity)
133+
check_model_key(entity, entity_is_parent)
114134

115135
# get source key, either data or filter key
116-
source_key = next(
117-
(sk for sk in cls.__source_keys if sk.label in entity.keys()),
118-
None)
119-
120-
# check if current keys has at least, data or filter key
121-
if source_key is None:
122-
raise KeyError("Missing 'data' or 'filter' key.")
136+
source_key = check_source_key(entity, cls._source_keys)
137+
source_data = entity[source_key]
123138

124-
source_data = entity[source_key.label]
139+
check_source_data(source_data, source_key)
125140

126141
if isinstance(source_data, list):
127-
if len(source_data) == 0:
128-
raise ValueError(f"'{source_key.label}' is empty.")
129142

130143
for item in source_data:
131144
if not source_key.is_valid_type(item):
@@ -137,9 +150,6 @@ def _validate(cls, entity: dict, is_parent=True, ref_prefix='!'):
137150
elif source_key.is_valid_type(source_data):
138151
# check if item is a relationship attribute
139152
cls._scan_attributes(source_data, ref_prefix)
140-
else:
141-
raise TypeError(
142-
f"Invalid type, '{source_key.label}' should be '{source_key.type}'")
143153

144154
@classmethod
145155
def _scan_attributes(cls, source_data: dict, ref_prefix):

0 commit comments

Comments
 (0)