#validict
validict is a Python module for comparing an unknown value to a desired template. It is intended for the top-level type to be a dict, but should be flexible enough to deal with lists or scalars (though if you're dealing at scalars, might I suggest running away from this and just using Python's isinstance). Important: this library specifically does not treat tuples as template expectations but instead as a set of expectations for a given position in a template.
Install with pip.
shell~$ pip install validict
Using validict is simple. First, declare your template:
from validict import validate
template = {
'name': str,
'age': int,
'pets': [
{
'name': str,
'kind': str
}
],
'parents': ([{'name': str}], int, None)
}
kid = {
'name': "Bart Simpson",
'age': 10,
'pets': [
{'name': "Santa's Little Helper", 'kind': "Dog"},
{'name': "Snowball II", 'kind': "Cat"}
],
'parents': [
{'name': "Homer Simpson"},
{'name': "Marge Simpson"}
]
}
validate(template, kid) # returns True
bad_kid = {
'name': "Nelson Muntz",
'age': 12
}
validate(template, bad_kid) # raises FailedValidationError
validate(template, bad_kid, quiet=True) # returns False
optional_kid = {
'name': "Milhouse Van Houten",
'age': 10,
'pets': [
{'name': "Lhasa Apso", 'kind': "Dog"}
],
'parents': None # Okay, not really, but for demonstration purposes...
}
validate(template, optional_kid) # returns TrueYou might be asking yourself -- or me -- "what the hell is this garbage?" Allow me to briefly explain, and you'll see that the template language is pretty simple.
-
We use plain, naked Python
types to indicate that the expected value for the given key should be an object of that type. So, if the passed-in dict has a value for'name'that isn't astr, validation fails. -
When we are expecting a
listof elements, we only need to declare in our template one instance of that item, if thelist's children are expected to be homogenous. Therefore,'pets'is expected to be alistofdicts, all containingstrvalue for keys'name'and'kind'. -
We can use a
tupleto declare that there may be multiple types of values, even including (but not demonstrated) further depth of structure. In the above, the value of'parents'can be adictwith parents' names, anint(perhaps representing the number of parents), orNone(if you're Batman). -
Calling
validatewith the template and unvalidated value, positionally, will result either in a return value ofTrueor a raise ofFailedValidationError. -
Calling
validateas above with the keyword parameterquiet=Truewill returnFalseinstead of raisingFailedValidationErroron validation failure. -
Allowing a
Nonetype as adictvalue or as a member of atuplesignifies that the value is optional. Using it in atupleallows you to declare that the value can either be matching some type or otherwise can be nothing at all. -
(Undemonstrated) Your template can declare scalar values as well. So if all inputs must have some specific K/V pair, you can declare that.
If you're using a web framework like, say, Falcon and you wanted to set up a before hook to validate the body of the incoming HTTP request, the function in this method is for you. At least that's why it's for me.
There is an experimental (read: not heavily tested) function in this module called deep_merge, which takes as its arguments two dictionaries. The second will be merged into the first, in a fashion such that keys are merged on every level instead of top-level key-values clobbering over all nested data.