Package: kobject
▄▄          ▄▄                      
▀████▀ ▀███▀          ▄██          ██                 ██   
  ██   ▄█▀             ██                             ██   
  ██ ▄█▀      ▄██▀██▄  ██▄████▄  ▀███  ▄▄█▀██ ▄██▀████████ 
  █████▄     ██▀   ▀██ ██    ▀██   ██ ▄█▀   ███▀  ██  ██   
  ██  ███    ██     ██ ██     ██   ██ ██▀▀▀▀▀▀█       ██   
  ██   ▀██▄  ██▄   ▄██ ██▄   ▄██   ██ ██▄    ▄█▄    ▄ ██   
▄████▄   ███▄ ▀█████▀  █▀█████▀    ██  ▀█████▀█████▀  ▀████
                                ██ ██                      
                                ▀███                       By CenturyBoys
                                
Know your object is a __init__ type validator for class and dataclassUsageKobject can be use inside default class declaration and with dataclasses. Kobject uses the__init__signature to check types.Default classesfromkobjectimportKobjectclassStubClass(Kobject):a_int:inta_bool:booldef__init__(self,a_int:int,a_bool:bool):self.a_int=a_intself.a_bool=a_boolself.__post_init__()instance=StubClass(a_int=1,a_bool=True)Notice that in the default class declaration you need to callself.__post_init__()at the end of the__init__declaration.DataclassfromdataclassesimportdataclassfromkobjectimportKobject@dataclassclassStubClass(Kobject):a_int:inta_bool:boolinstance=StubClass(a_int=1,a_bool=True)By default, dataclass callsself.__post_init__()at the end of the__init__declarationdoc.ExceptionKobject raisesTypeErrorwith all validation errors, that means it checks all your object's attributes before raising theTypeError. Types like List and Tuple will have all their elements checked.fromdataclassesimportdataclassfromkobjectimportKobjectfromtypingimportList,Tuple@dataclassclassStubClass(Kobject):a_list_int:List[int]a_tuple_bool:Tuple[bool]instance=StubClass(a_list_int=[1,"",2,""],a_tuple_bool=["",True])Traceback(mostrecentcalllast):
...
TypeError:Class'StubClass'typeerror:Wrongtypefora_list_int:typing.List[int]!='<class 'list'>'Wrongtypefora_tuple_bool:typing.Tuple[bool]!='<class 'list'>'You can use lazy validation to improve performance, the code will stop in the first found error for this usefromkobjectimportKobjectKobject.set_lazy_type_check(status=True)Default valueKobject supports default values and will check them before any validation, that means if you declare aa_bool: bool = Noneit will not raise an error.fromdataclassesimportdataclassfromkobjectimportKobjectclassStubClass(Kobject):a_bool:bool=Nonedef__init__(self,a_bool:bool=10):self.a_bool=a_boolself.__post_init__()@dataclassclassStubDataClass(Kobject):a_bool:bool=10Custom exceptionBy default, Kobject raise aTypeErrorbut you can override this exception usingset_validation_custom_exceptionfor type validation orset_content_check_custom_exceptionfor field check on from JSON operation.fromdataclassesimportdataclassfromkobjectimportKobjectclassCustomException(Exception):passKobject.set_validation_custom_exception(CustomException)#Kobject.set_content_check_custom_exception(CustomException)@dataclassclassStubClass(Kobject):a__int:intinstance=StubClass(a__int="")Traceback(mostrecentcalllast):
...
CustomException:Class'StubClass'typeerror:Wrongtypefora__int:<class'int'>!='<class 'str'>'ToJSONKobject has his own implementation to parse class instance to a JSON representation.fromdataclassesimportdataclassfromtypingimportList,TuplefromkobjectimportKobject@dataclassclassBaseC(Kobject):a_int:inta_str:stra_list_of_int:List[int]a_tuple_of_bool:Tuple[bool]instance=BaseC(a_int=1,a_str="lala",a_list_of_int=[1,2,3],a_tuple_of_bool=(True,))json_bytes=instance.to_json()print(json_bytes)b'{"a_int": 1, "a_str": "lala", "a_list_of_int": [1, 2, 3], "a_tuple_of_bool": [true]}'For complex values ToJSON exposeset_encoder_resolverto handler it.Notest, Before encoding the object to JSON bytes, it will be represented byself.dict(). Some objects, such asdatetime.datetime, can be useful in dictionary structures but are not JSON serializable. In such cases, you can use theon_dict: boolparameter in theKobject.set_encoder_resolver()method to encode only when JSON bytes are required, not in its dictionary representation.fromdataclassesimportdataclassfromdatetimeimportdatetimefromtypingimportListfromuuidimportUUIDfromkobjectimportKobject@dataclassclassBaseA(Kobject):a_datetime:datetime@dataclassclassBaseB:a_uuid:UUID@dataclassclassBaseC(Kobject):a_base_a:BaseAa_base_b:BaseBa_list_of_base_a:List[BaseA]Kobject.set_encoder_resolver(datetime,lambdavalue:str(value),False)Kobject.set_encoder_resolver(BaseB,lambdavalue:{"a_uuid":str(value.a_uuid)})instance=BaseC(a_base_a=BaseA(a_datetime=datetime.fromisoformat("2023-02-01 17:38:45.389426")),a_base_b=BaseB(a_uuid=UUID("1d9cf695-c917-49ce-854b-4063f0cda2e7")),a_list_of_base_a=[BaseA(a_datetime=datetime.fromisoformat("2023-02-01 17:38:45.389426"))])dict_repr=instance.dict()isinstance(dict_repr["a_base_a"]["a_datetime"],datetime)json_bytes=instance.to_json()print(json_bytes)b'{"a_base_a": {"a_datetime": "2023-02-01 17:38:45.389426"}, "a_base_b": {"a_uuid": "1d9cf695-c917-49ce-854b-4063f0cda2e7"}, "a_list_of_base_a": [{"a_datetime": "2023-02-01 17:38:45.389426"}]}'FromJSONKobject has his own implementation to parse JSON to a class instance.fromdataclassesimportdataclassfromtypingimportList,TuplefromkobjectimportKobject@dataclassclassBaseC(Kobject):a_int:inta_str:stra_list_of_int:List[int]a_tuple_of_bool:Tuple[bool]payload=(b'{"a_int": 1,"a_str": "lala","a_list_of_int": [1,2,3],'b'"a_tuple_of_bool": [true]}')instance=BaseC.from_json(payload=payload)print(instance)BaseC(a_int=1,a_str='lala',a_list_of_int=[1,2,3],a_tuple_of_bool=(True,))For complex values FromJSON exposeset_decoder_resolverto handler it.fromdatetimeimportdatetimefromdataclassesimportdataclassfromtypingimportListfromuuidimportUUIDfromkobjectimportKobject@dataclassclassBaseA(Kobject):a_datetime:datetime@dataclassclassBaseB:a_uuid:UUID@dataclassclassBaseC(Kobject):a_base_a:BaseAa_base_b:BaseBa_list_of_base_a:List[BaseA]Kobject.set_decoder_resolver(datetime,lambdaattr_type,value:datetime.fromisoformat(value)ifisinstance(value,str)elsevalue,)Kobject.set_decoder_resolver(BaseB,lambdaattr_type,value:attr_type(a_uuid=UUID(value["a_uuid"]))ifisinstance(value,dict)elsevalue,)payload=(b'{"a_base_a": {"a_datetime": "2023-02-01 17:38:45.389426"},"a_base_b": {"a_'b'uuid":"1d9cf695-c917-49ce-854b-4063f0cda2e7"}, "a_lis'b't_of_base_a": [{"a_datetime": "2023-02-01 17:38:45.389426"}]}')instance=BaseC.from_json(payload=payload)print(instance)BaseC(a_base_a=BaseA(a_datetime=datetime.datetime(2023,2,1,17,38,45,389426)),a_base_b=BaseB(a_uuid=UUID('1d9cf695-c917-49ce-854b-4063f0cda2e7')),a_list_of_base_a=[BaseA(a_datetime=datetime.datetime(2023,2,1,17,38,45,389426))])