Releases: mansam/validator.py
1.3.1
v0.8.0 -- Extensions and More Validators
Extensions
The default module was getting a bit unwieldy, so I've created a new validator.ext
submodule to contain validators that aren't common enough to be in the main namespace. Related validators should be grouped together in their own submodules under ext
, e.g. all validators related to foo
should live in a module called validator.ext.foo
. One-offs can either go in validator.ext
or in their own submodule, depending on the scope and likelihood of further expansion. I've started things off by putting the ArgSpec
validator into the ext
module since it was pretty obscure.
New Validators
This release features two new validators for working with collections, Contains
and Length
.
Contains
Contains
is pretty straight forward, you can use it to ensure that a collection contains a particular value, like so:
# Example:
validation = {
"field": [Contains(3)]
}
passes = {"field": [1, 2, 3]}
fails = {"field": [4, 5, 6]}
This'll work with any kind of collection that supports in
, so strings, dictionaries, lists, sets, and more are all fair game.
Length
Length
lets you ensure that a collection is of some minimum and optionally maximum length.
# Example:
validations = {
"field": [Length(0, maximum=5)]
}
passes = {"field": "hello"}
fails = {"field": "hello world"}
v0.6.0 -- Nested Validations
Nested Validations
This release adds support for nested validations, something that should have been there all along. Essentially, this allows a list of validations to contain a dictionary of yet more validations in order to accommodate writing validations for nested dictionaries. Here's an example:
validator = {
"foo": [Required, Equals(1)],
"bar": [Required, {
"baz": [Required, Equals(2)],
"qux": [Required, {
"quux": [Required, Equals(3)]
}]
}
]
}
test_case = {
"foo": 1,
"bar": {
"baz": 2,
"qux": {
"quux": 3
}
}
}
The above example says that the bar
key is required and also represents a dictionary that also has its own set of validations. For good measure, this example has yet another dictionary under the qux
key. As long as everything checks out, validate
will return the normal (True, {})
response indicating success.
In the event of failure, you get an appropriately nested error message like those produced by the If(Then()) conditional validator. Here's an example of what such an error might look like:
>>> validate(fails, test_case)
(False,
{'bar': [{'baz': ['must be equal to 3'],
'qux': [{'quux': ['must be equal to 4']}]}],
'foo': ['must be equal to 2']})
Changes to Not(validator)
Up until this release, all of the negated versions of validation errors were produced by the Not
validator. This was not a sensible long term solution. All validators are now responsible for their own negated error messages and as such now have their own not_message
attribute as an analogue of the err_message
attribute they already had. This will make it easier to extend the library's capabilities with custom, and it certainly makes the Not
validator less messy.
Generic Errors
Related to the change to negated error messages, all validators will now have generic error messages and negated error messages provided for them in the event they don't provide their own. This manifests as a simple "validation failed"
.
v0.4.1 -- Conditional Validators and Sphinx Docs
This release added conditional validators. In some cases you might want to apply some rules only if other validations pass. You can do that with the If(validator, Then(validation)) construct that validator.py provides. For example, you might want to ensure that pet['name'] is a cat’s name, but only if pet['type'] == 'cat'. To do this, you’d use the If validator on the key that serves as the condition for the other set of the rules.
pet = {
"name": "whiskers",
"type": "cat"
}
cat_name_rules = {
"name": [In(["whiskers", "fuzzy", "tiger"])]
}
dog_name_rules = {
"name": [In(["spot", "ace", "bandit"])]
}
validation = {
"type": [
If(Equals("cat"), Then(cat_name_rules)),
If(Equals("dog"), Then(dog_name_rules))
]
}
>>> validate(validation, pet)
(True, {})
# Success!
A failed conditional validation will give you appropriately nested error messages so you know exactly where things went wrong.
pet = {"type":"cat", "name": "lily"}
>>> validate(validation, pet)
(False, {'type': [{'name': ["must be one of ['whiskers', 'fuzzy', 'tiger']"]}]})
v0.3.1 -- InstanceOf and SubclassOf
This update adds the InstanceOf and SubclassOf validators. True to their names, InstanceOf requires that a value be an instance of a base class or its subclasses, and SubclassOf requires that a value actually be a class that inherits from the specified class.
InstanceOf
# InstanceOf Example:
validations = {
"field": [InstanceOf(basestring)]
}
passes = {"field": ""} # is a <'str'>, subclass of basestring
fails = {"field": str} # is a <'type'
SubclassOf:
# SubclassOf Example
validations = {
"field": [SubclassOf(basestring)]
}
passes = {"field": str} # is a subclass of basestring
fails = {"field": int}
Thanks to @ryansb for the SubclassOf validator he submitted in #1.