2222SOFTWARE.
2323"""
2424
25+ from . import errors
26+
2527
2628class 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
85109class 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