11
11
dataclass ,
12
12
is_dataclass ,
13
13
make_dataclass ,
14
+ fields
14
15
)
15
16
from typing import Any , Optional , Union
16
17
from functools import partial
17
18
from enum import EnumMeta
19
+ from operator import attrgetter
18
20
from orjson import OPT_INDENT_2
19
21
from datamodel .converters import parse_type
20
22
from datamodel .fields import Field
@@ -40,6 +42,7 @@ class Meta:
40
42
dsn : Optional [str ] = None
41
43
datasource : Optional [str ] = None
42
44
connection : Optional [Callable ] = None
45
+ remove_nulls : bool = False
43
46
44
47
def set_connection (cls , conn : Callable ):
45
48
cls .connection = conn
@@ -89,7 +92,7 @@ def create_dataclass(
89
92
create_dataclass.
90
93
Create a Dataclass from a simple Class
91
94
"""
92
- dc = dataclass (unsafe_hash = True , init = True , order = False , eq = True , frozen = frozen )(new_cls )
95
+ dc = dataclass (unsafe_hash = True , repr = False , init = True , order = False , eq = True , frozen = frozen )(new_cls )
93
96
setattr (dc , "__setattr__" , _dc_method_setattr )
94
97
# adding a properly internal json encoder:
95
98
dc .__encoder__ = DefaultEncoder ()
@@ -209,11 +212,31 @@ def __getitem__(self, item):
209
212
def column (self , name ):
210
213
return self .__columns__ [name ]
211
214
215
+ def __repr__ (self ):
216
+ nodef_f_vals = (
217
+ (f .name , attrgetter (f .name )(self ))
218
+ for f in fields (self )
219
+ if attrgetter (f .name )(self ) != f .default
220
+ )
221
+ nodef_f_repr = ", " .join (f"{ name } ={ value } " for name , value in nodef_f_vals )
222
+ return f"{ self .__class__ .__name__ } ({ nodef_f_repr } )"
223
+
224
+ def remove_nulls (self , obj : Any ) -> dict [str , Any ]:
225
+ """Recursively removes any fields with None values from the given object."""
226
+ if isinstance (obj , list ):
227
+ return [self .remove_nulls (item ) for item in obj ]
228
+ elif isinstance (obj , dict ):
229
+ return {key : self .remove_nulls (value ) for key , value in obj .items () if value is not None }
230
+ else :
231
+ return obj
232
+
212
233
def dict (self ):
234
+ if self .Meta .remove_nulls is True :
235
+ return self .remove_nulls (asdict (self , dict_factory = dict ))
213
236
return asdict (self )
214
237
215
238
def to_dict (self ):
216
- return asdict ( self )
239
+ return self . dict ( )
217
240
218
241
def json (self , ** kwargs ):
219
242
encoder = self .__encoder__
@@ -333,6 +356,15 @@ def __post_init__(self) -> None:
333
356
self ._validation ()
334
357
except RuntimeError as err :
335
358
logging .exception (err )
359
+ ### Post Init
360
+ ## check if remove nulls:
361
+ # print('META >>> ', self.Meta.nulls)
362
+ # if self.Meta.remove_nulls is True:
363
+ # null_fields = [field_name for field_name, value in self.__dict__.items() if value is None]
364
+ # print('NULL FIELDS >> ', null_fields)
365
+ # for field_name in null_fields:
366
+ # delattr(self, field_name)
367
+
336
368
337
369
def is_callable (self , value ) -> bool :
338
370
is_missing = (value == _MISSING_TYPE )
@@ -559,11 +591,11 @@ def schema(cls, as_dict: bool = False) -> Any:
559
591
"enum" : list (map (lambda c : c .value , _type ))
560
592
}
561
593
elif isinstance (_type , ModelMeta ):
562
-
594
+
563
595
t = 'object'
564
596
enum_type = None
565
597
sch = _type .schema (as_dict = True )
566
-
598
+
567
599
if 'fk' in field .metadata :
568
600
api = field .metadata ['api' ] if 'api' in field .metadata else sch ['table' ]
569
601
fk = field .metadata ['fk' ].split ("|" )
@@ -574,7 +606,7 @@ def schema(cls, as_dict: bool = False) -> Any:
574
606
}
575
607
else :
576
608
ref = sch ['$id' ]
577
-
609
+
578
610
defs [name ] = sch
579
611
else :
580
612
ref = None
0 commit comments