Package: validatedata
ValidatedataAn easier way to validate data in pythonInstallationpip install validatedataUsageThere are three ways to validate data:1. Using the validate_types decoratorfromvalidatedataimportvalidate_types@validate_types()defsum(num1:int,num2:int):returnnum1+num2print(sum(4,6))# raises exceptionsum('bread','butter')2. Using the validate decoratorfromvalidatedataimportvalidaterules=['int','int']@validate(rules)defsum(a,b):returna+bParametersrule -str or list or tuple or dict- rule(s) used to validate data. They should have the same index as the data.raise_exceptions -bool- whether exceptions should be thrown when data is invalid. Default is Falseis_class -bool- required for class methods that don't have theselfparameterkwds -dict- takes configuration parameters that aren't explicitly catered for, e.glog_errorsandgroup_errorsSetlog_errorsto True if you wish to log unhandled errors occuring in the background i.e@validate(rules, ..., kwds={'log_errors': True})Setgroup_errorsto False if you wish to disable grouping of errorsWhen the data does not match the rules, a dictionary is returned in the following format:{'errors':[[group1],[group2],...]}or{'errors':[error1,error2,...]}3. Using the validate_data functionfromvalidatedataimportvalidate_datarules=[{'type':'int','range':(1,'any'),'range-message':'value should be an integer greater than zero'},{'type':'int','range':(1,'any')}]defsum(a,b):total=0result=validate_data(data=[a,b],rule=rules)ifresult.ok:total=a+breturntotalCustom messages can be set by adding a key that matches the format,{rule}-messagee.g range-message, length-message, et cetera. They are recommended since the present defaults might be too generic in some circumstancesParametersdata -list or str or dict- the data to be validatedrule - same as decoratorraise_exceptions - same as decoratoris_class - same as decoratorkwds - same as decoratorWhen thedataparameter is a dict,ruleshould also be a dict in this format:{'keys':OrderedDict({'key1':{'type':'<type>',...},'key2':{'type':'int','range':(5,1000)}})}For Python versions>= 3.7you can replaceOrderedDictwith a standard dict since they are said to maintain insertion orderA SimpleNamespace object with the attributesokanderrorsis returned. It can be accessed like so:result=validate_data(...)ifresult.ok:pass# do xelse:errors=result.errorspass# do yTypes (validateandvalidate_data)booldateemailevenfloatintoddstrdictlistregexsettupleobjectRuleslength - integer - expected length of a string, int, or objectcontains - string or tuple of values expected in an objectexcludes - string or tuple of values not permittedoptions - tuple - a tuple of permitted valuesstrict - boolean indicating whether data should be type cast or notexpression - string - ensures data matches a given regular expressiontype - string - specifies type of data expected. Should always be includedrange - tuple - specifies permitted range or values. Used with numbers and datesstartswith - object - string, int, et cetera that a type starts withendswith - object - string, int, et cetera that a type ends withExamplessignup_rules=[{'type':'str','expression':r'^[^\d\W_]+[\w\d_-]{2,31}$','expression-message':'invalid username'},'email:msg:invalid email',{'type':'str','expression':r'(?=\S*[a-z])(?=\S*[A-Z])(?=\S*\d)(?=\S*[^\w\s])\S{8,}$','message':'password must contain a number, an uppercase letter, a symbol, and should be at least 8 characters long without spaces'}]classUser:@validate(signup_rules,raise_exceptions=True)defsignup(self,username,email,password):return"Account Created"user=User()response=user.signup('helterskelter','paddle','Arosebyanyname?1')# response = user.signup('helterskelter', 'paddle@gmail.com', 'Arosebyanyname?1')print(response)rules=['str:20','int:10','list:5']rules=[{'type':'str','length':20},{'type':'int','length':10},{'type':'list','length':5}]rules=[{'type':'date','range':('01-Jan-2021','any'),'range-message':'the lowest date is 1st Jan 2021'}]classUser:@classmethod@validate(rule=['str','str'],is_class=True)defformat_name(cls,firstname,lastname):returnf'{firstname}{lastname}'Additional NotesThe functionality of a rule depends on the type it's working upon, e.g{'type':'int','range':(2,100)}# int >= 2 and <= 100{'type':'str','range':(2,100)}# string of variable length: len(s) >= 2 and len(s) <= 100The equivalence rulesequal toandnot equal toaren't included but their effect can be achieved usingoptionsandexcludes{...,'options':(200,)}{...,'excludes':('Bill',...)}Objectcaters to custom typesclassPerson:passrules=[{'type':'object','object':Person,'message':'Person object expected'}]result=validate_data(data=[12],rule=rules)# person = Person()# result = validate_data(data=[person], rule=rules)The current version does not support nested dataLicenseMIT