11
11
from enum import EnumMeta
12
12
from uuid import UUID
13
13
from orjson import OPT_INDENT_2
14
- from .converters import parse_type , slugify_camelcase
14
+ from .converters import parse_basic , parse_type , slugify_camelcase
15
15
from .fields import Field
16
16
from .types import JSON_TYPES , Text
17
- from .validation import validator , is_callable , is_empty , is_dataclass
17
+ from .validation import (
18
+ _validation ,
19
+ is_callable ,
20
+ is_empty ,
21
+ is_dataclass ,
22
+ is_primitive
23
+ )
18
24
from .exceptions import ValidationError
19
25
from .parsers .encoders import json_encoder
20
26
from .abstract import ModelMeta , Meta
@@ -81,13 +87,10 @@ def __post_init__(self) -> None:
81
87
for name , f in self .__columns__ .items ():
82
88
try :
83
89
value = getattr (self , name )
84
- self ._calculate_value_ (name , value , f )
85
- error = self ._validation_ (name , value , f )
86
- if error :
90
+ if (error := self ._process_field_ (name , value , f )):
87
91
errors [name ] = error
88
92
except RuntimeError as err :
89
93
logging .exception (err )
90
-
91
94
if errors :
92
95
if self .Meta .strict is True :
93
96
raise ValidationError (
@@ -100,15 +103,6 @@ def __post_init__(self) -> None:
100
103
else :
101
104
object .__setattr__ (self , "__valid__" , True )
102
105
103
- def is_valid (self ) -> bool :
104
- """is_valid.
105
-
106
- returns True when current Model is valid under datatype validations.
107
- Returns:
108
- bool: True if current model is valid.
109
- """
110
- return bool (self .__valid__ )
111
-
112
106
@classmethod
113
107
def add_field (cls , name : str , value : Any = None ) -> None :
114
108
if cls .Meta .strict is True :
@@ -158,52 +152,96 @@ def set(self, name: str, value: Any) -> None:
158
152
else :
159
153
setattr (self , name , value )
160
154
161
- def _calculate_value_ (self , name : str , value : Any , f : Field ) -> None :
162
- _type = f .type
163
- _encoder = f .metadata .get ('encoder' )
164
-
165
- if f .default is not None and is_callable (value ):
166
- return
167
-
168
- # Handle dataclass types
169
- if is_dataclass (_type ):
170
- new_val = self ._handle_dataclass_type (value , _type )
171
- elif _type .__module__ == 'typing' :
172
- new_val = parse_type (_type , value , _encoder )
173
- elif isinstance (value , list ) and hasattr (_type , '__args__' ):
174
- new_val = self ._handle_list_of_dataclasses (value , _type )
175
- else :
176
- new_val = self ._handle_default_case (value , f )
177
-
178
- setattr (self , name , new_val )
155
+ def _handle_default_value (self , value , f , name ) -> Any :
156
+ # Calculate default value
157
+ if is_callable (value ):
158
+ if value .__module__ != 'typing' :
159
+ try :
160
+ new_val = value ()
161
+ except TypeError :
162
+ try :
163
+ new_val = f .default ()
164
+ except TypeError :
165
+ new_val = None
166
+ setattr (self , name , new_val )
167
+ elif is_callable (f .default ) and value is None :
168
+ # Set the default value first
169
+ try :
170
+ new_val = f .default ()
171
+ except (AttributeError , RuntimeError ):
172
+ new_val = None
173
+ setattr (self , name , new_val )
174
+ value = new_val # Return the new value
175
+ elif not isinstance (f .default , _MISSING_TYPE ) and value is None :
176
+ setattr (self , name , f .default )
177
+ value = f .default
178
+ return value
179
179
180
180
def _handle_dataclass_type (self , value , _type ):
181
- if hasattr (self .Meta , 'no_nesting' ):
182
- return value
183
- if value is None or is_dataclass (value ):
184
- return value
185
- if isinstance (value , dict ):
186
- return _type (** value )
187
- if isinstance (value , list ):
188
- return _type (* value )
189
- return value if isinstance (value , (int , str , UUID )) else _type (value )
181
+ try :
182
+ if hasattr (self .Meta , 'no_nesting' ):
183
+ return value
184
+ if value is None or is_dataclass (value ):
185
+ return value
186
+ if isinstance (value , dict ):
187
+ return _type (** value )
188
+ if isinstance (value , list ):
189
+ return _type (* value )
190
+ return value if isinstance (value , (int , str , UUID )) else _type (value )
191
+ except Exception as exc :
192
+ raise ValueError (
193
+ f"Invalid value for { _type } : { value } , error: { exc } "
194
+ )
190
195
191
196
def _handle_list_of_dataclasses (self , value , _type ):
192
197
try :
193
198
sub_type = _type .__args__ [0 ]
194
199
if is_dataclass (sub_type ):
195
- return [sub_type (** item ) if isinstance (item , dict ) else item for item in value ]
200
+ return [
201
+ sub_type (** item ) if isinstance (item , dict ) else item for item in value
202
+ ]
196
203
except AttributeError :
197
204
pass
198
205
return value
199
206
200
- def _handle_default_case (self , value , f ):
207
+ def _process_field_ (self , name : str , value : Any , f : Field ) -> dict [Any ]:
208
+ _type = f .type
209
+ _encoder = f .metadata .get ('encoder' )
210
+ new_val = value
211
+
201
212
if is_empty (value ):
202
- return f .default_factory if isinstance (f .default , _MISSING_TYPE ) else f .default
203
- try :
204
- return parse_type (f .type , value , f .metadata .get ('encoder' ))
205
- except (TypeError , ValueError ) as ex :
206
- raise ValueError (f"Wrong Type for { f .name } : { f .type } , error: { ex } " ) from ex
213
+ new_val = f .default_factory if isinstance (f .default , (_MISSING_TYPE )) else f .default
214
+ setattr (self , name , new_val )
215
+
216
+ if f .default is not None :
217
+ value = self ._handle_default_value (value , f , name )
218
+
219
+ if is_primitive (_type ):
220
+ try :
221
+ new_val = parse_basic (f .type , value , _encoder )
222
+ return self ._validation_ (name , new_val , f , _type )
223
+ except (TypeError , ValueError ) as ex :
224
+ raise ValueError (
225
+ f"Wrong Type for { f .name } : { f .type } , error: { ex } "
226
+ ) from ex
227
+ elif isinstance (value , list ) and hasattr (_type , '__args__' ):
228
+ new_val = self ._handle_list_of_dataclasses (value , _type )
229
+ return self ._validation_ (name , new_val , f , _type )
230
+ elif _type .__module__ == 'typing' :
231
+ new_val = parse_type (_type , value , _encoder )
232
+ return self ._validation_ (name , new_val , f , _type )
233
+ elif is_dataclass (_type ):
234
+ new_val = self ._handle_dataclass_type (value , _type )
235
+ return self ._validation_ (name , new_val , f , _type )
236
+ else :
237
+ try :
238
+ new_val = parse_type (f .type , value , _encoder )
239
+ except (TypeError , ValueError ) as ex :
240
+ raise ValueError (
241
+ f"Wrong Type for { f .name } : { f .type } , error: { ex } "
242
+ ) from ex
243
+ # Then validate the value
244
+ return self ._validation_ (name , new_val , f , _type )
207
245
208
246
def _field_checks_ (self , f : Field , name : str , value : Any ) -> None :
209
247
# Validate Primary Key
@@ -238,43 +276,21 @@ def _field_checks_(self, f: Field, name: str, value: Any) -> None:
238
276
except KeyError :
239
277
pass
240
278
241
- def _validation_ (self , name : str , value : Any , f : Field ) -> Optional [Any ]:
279
+ def _validation_ (self , name : str , value : Any , f : Field , _type : Any ) -> Optional [Any ]:
242
280
"""
243
281
_validation_.
244
282
TODO: cover validations as length, not_null, required, max, min, etc
245
283
"""
246
- annotated_type = f .type
247
284
val_type = type (value )
285
+ # Set the current Value
286
+ setattr (self , name , value )
248
287
249
- # Calculate default value
250
- if f .default is not None :
251
- if is_callable (value ):
252
- if value .__module__ != 'typing' :
253
- try :
254
- new_val = value ()
255
- except TypeError :
256
- try :
257
- new_val = f .default ()
258
- except TypeError :
259
- new_val = None
260
- setattr (self , name , new_val )
261
- elif is_callable (f .default ) and value is None :
262
- # Set the default value first
263
- try :
264
- new_val = f .default ()
265
- except (AttributeError , RuntimeError ):
266
- new_val = None
267
- setattr (self , name , new_val )
268
- value = new_val # Return the new value
269
- elif not isinstance (f .default , _MISSING_TYPE ) and value is None :
270
- setattr (self , name , f .default )
271
- value = f .default
272
-
273
- if val_type == type or value == annotated_type or is_empty (value ):
288
+ if val_type == type or value == _type or is_empty (value ):
274
289
self ._field_checks_ (f , name , value )
275
290
else :
276
291
# capturing other errors from validator:
277
- return validator (f , name , value , annotated_type )
292
+ # return _validation(f, name, value, _type, val_type)
293
+ return None
278
294
279
295
def get_errors (self ):
280
296
return self .__errors__
0 commit comments