Pyvaru is a simple, flexible and unobtrusive data validation library for Python 3 (3.4+), based on the concept of validation rules.
From the software design point of view, a rule is a class implementing the strategy pattern,
by encapsulating the validation logic in an interface method called apply().
The library already offers a series of common validation rules like:
TypeRule(it checks that the target value is an instance of the expected type)FullStringRule(it checks the the target value is a string with content)ChoiceRule(it checks that the target value is contained in a list of available options)MinValueRule(it checks that the target value is >= x) *MaxValueRule(it checks that the target value is <= x) *MinLengthRule(it checks that the target value length is >= x) *MaxLengthRule(it checks that the target value length is <= x) *RangeRule(it checks that the target value is contained in a givenrange)IntervalRule(it checks that the target value is contained in a given interval)PatternRule(it checks that the target value matches a given regular expression)PastDateRule(it checks that the target value is a date in the past)FutureDateRule(it checks that the target value is a date in the future)UniqueItemsRule(it checks that the target iterable does not contain duplicated items)
* where "x" is a provided reference value
The developer is then free to create his custom rules by extending the abstract ValidationRule
and implementing the logic in the apply() method. For example:
classContainsHelloRule(ValidationRule):
defapply(self) ->bool:
return'hello'inself.apply_toThese rules are then executed by a Validator, which basically executes them in the provided
order and eventually returns a ValidationResult containing the validation response.
pip install pyvaru
Given an existing model to validate, like the one below (but it could be a simple dictionary or any data structure since pyvaru does not make any assumption on the data format):
classUser:
def__init__(self, first_name: str, last_name: str, date_of_birth: datetime, sex: str):
self.first_name=first_nameself.last_name=last_nameself.date_of_birth=date_of_birthself.sex=sexWe have to define a validator, by implementing the get_rules() method and for each field we want to
validate we have to provide one or more proper rule(s).
frompyvaruimportValidatorfrompyvaru.rulesimportTypeRule, FullStringRule, ChoiceRule, PastDateRuleclassUserValidator(Validator):
defget_rules(self) ->list:
user=self.data# type: Userreturn [
TypeRule(apply_to=user,
label='User',
valid_type=User,
error_message='User must be an instance of user model.',
stop_if_invalid=True),
FullStringRule(lambda: user.first_name, 'First name'),
FullStringRule(lambda: user.last_name, 'Last name'),
ChoiceRule(lambda: user.sex, 'Sex', choices=('M', 'F')),
PastDateRule(lambda: user.date_of_birth, 'Date of birth')
]It's also possible to create groups of rules by using RuleGroup and avoid code duplication if multiple rules should
be applied to the same field. So this code:
defget_rules(self) ->list:
return [
TypeRule(lambda: self.data.countries, 'Countries', valid_type=list),
MinLengthRule(lambda: self.data.countries, 'Countries', min_length=1),
UniqueItemsRule(lambda: self.data.countries, 'Countries')
]can be replaced by:
defget_rules(self) ->list:
return [
RuleGroup(lambda: self.data.countries,
'Countries',
rules=[(TypeRule, {'valid_type': list}),
(MinLengthRule, {'min_length': 1}),
UniqueItemsRule])
]Finally we have two choices regarding how to use our custom validator:
- As a context processor:
withUserValidator(user):
# do whatever you want with your valid modelIn this case the code inside with will be executed only if the validation succeed, otherwise a
ValidationException (containing a validation_result property with the appropriate report) is raised.
- By invoking the
validate()method (which returns aValidationResult)
validation=UserValidator(user).validate()
ifvalidation.is_successful():
# do whatever you want with your valid modelelse:
# you can take a proper action and access validation.errors# in order to provide a useful message to the application user,# write logs or whateverAssuming we have a instance of an User configured as the one below:
user=User(first_name=' ',
last_name=None,
date_of_birth=datetime(2020, 1, 1),
sex='unknown')By running a validation with the previous defined rules we will obtain a ValidationResult with the following errors:
{
'First name': ['String is empty.'],
'Last name': ['Not a string.'],
'Sex': ['Value not found in available choices.'],
'Date of birth': ['Not a past date.']
}Go to: http://pyvaru.readthedocs.io/en/latest/contents.html
Pyvaru is developed and maintained by Davide Zanotti.
Blog: http://www.daveoncode.com
Twitter: https://twitter.com/daveoncode