Package: validate-it
Validate-itAboutInstallationSupported fieldsValidation exampleDataclass exampleSimple mapping exampleNested mapping exampleRequirementsAboutUltimate data validation tool built on top of the typing moduleFeatures:validation by type hintsvalidation on__init__:SomeModel(**kwargs)validation on__setattr__:some_instance.some_field = valuebuilt-in options for types:min_value,max_value(based on<and>)min_length,max_length,size(based onlen())cast for incoming value and outgoing value:Options(parser=int, serializer=str)aliasfor incoming keys andrenamefor outgoing keys:d: int = Options(alias='dyn', rename='dynamic')validation by listallowed values:Options(allow=[1, 2, 3])validation by custom list ofvalidators:Options(validators=[is_odd, is_even])auto pack nested values:data: List[SomeModel] = Options(auto_pack=True, packer=SomeModel)all thisoptionscan be callable:Options(min_value=dynamic_min_value)InstallationWith pip:pipinstallvalidate-itSupported fieldsimportrefromdatetimeimportdatetimefromtypingimportDict,List,Union,Optionalfromvalidate_itimportschema,OptionsclassIsNotEmailError(Exception):passdefis_email(name,key,value,root):ifnotre.match(r"[^@]+@[^@]+\.[^@]+",value):raiseIsNotEmailError(f"{key}: is not email")returnvalue@schemaclassExample:# required fieldsfield_a:datetimefield_b:float# required fields with defaultsfield_c:str="unknown"field_d:int=9# required fields with nested typesfield_e:Dict[int,str]field_f:List[int]# optional fieldsfield_g:Optional[int]field_h:Union[int,None]# equivalent of Optional[int]# with some validators:fields_i:int=Options(default=0,max_value=100,min_value=100)fields_j:str=Options(size=10)fields_k:str=Options(min_length=10,max_length=20)fields_l:List[str]=Options(size=5)fields_m:str=Options(validators=[is_email])fields_n:int=Options(allowed=[1,2,3])# with search (input) alias:fields_o:int=Options(alias="field_n")# with rename (output) alias:fields_p:int=Options(rename="field_q")# with serializer used in #to_dict(), outgoing value is str typefields_q:int=Options(serializer=str)# with parser used in #from_dict() or direct setattr, incoming value will be parsed as intfields_r:int=Options(parser=int)Validation examplefromtypingimportListfromvalidate_itimport*@schemaclassSimple:a:intb:intsimple=Simple(a=1,b=2)simple.a=2simple.b=3try:simple.a='not int'exceptTypeError:print("Wrong type")@schemaclassOwner:first_name:strlast_name:str@schemaclassCharacteristics:cc:float=Options(min_value=0.0)hp:int=Options(min_value=0)@schemaclassCar:name:str=Options(min_length=2,max_length=20)owners:List[Owner]=Options(auto_pack=True,packer=pack_value)characteristics:Characteristics=Options(default=lambda:{"cc":0.0,"hp":0},auto_pack=True,packer=pack_value)convert:bool=Options(parser=bool)_data={"name":"Shelby GT500","owners":[{"first_name":"Randall","last_name":"Raines",}],"characteristics":{"cc":4.7,"hp":306},"unknown_field":10,"convert":1}_expected={"name":"Shelby GT500","owners":[{"first_name":"Randall","last_name":"Raines",}],"characteristics":{"cc":4.7,"hp":306},"convert":"1"}car=Car(**_data)assertto_dict(car)==_expectedDataclass examplefromvalidate_itimport*fromdataclassesimportdataclass@schema@dataclassclassSimple:a:intb:intsimple=Simple(a=1,b=2)simple.a=2simple.b=3try:simple.a='not int'exceptTypeError:print("Wrong type")Simple mapping examplefromvalidate_itimport*@schemaclassUser:first_name:str=Options(alias="f")last_name:str=Options(alias="l")_in_data={"f":"John","l":"Connor"}user=User(**_in_data)assertto_dict(user)=={"first_name":"John","last_name":"Connor"}Nested mapping examplefromvalidate_itimport*fromaccordionimportcompress@schemaclassPlayer:nickname:str=Options(alias="info.nickname")intelligence:int=Options(alias="characteristics/0")dexterity:int=Options(alias="characteristics/1")strength:int=Options(alias="characteristics/2")vitality:int=Options(alias="characteristics/3")_in_data={"info":{"nickname":"Killer777",},"characteristics":[7,55,11,44]}player=Player(**compress(_in_data))assertto_dict(player)=={"nickname":"Killer777","intelligence":7,"dexterity":55,"strength":11,"vitality":44}and back:fromvalidate_itimport*fromaccordionimportexpand@schemaclassPlayer:nickname:str=Options(rename="info.nickname")intelligence:int=Options(rename="characteristics/0")dexterity:int=Options(rename="characteristics/1")strength:int=Options(rename="characteristics/2")vitality:int=Options(rename="characteristics/3")_in_data={"nickname":"Killer777","intelligence":7,"dexterity":55,"strength":11,"vitality":44}player=Player(**_in_data)assertexpand(to_dict(player))=={"info":{"nickname":"Killer777",},"characteristics":[7,55,11,44]}RequirementsTested withpython3.6,python3.7,pypy3.6-7.0.0