Skip to content

Releases: mansam/validator.py

1.3.1

11 Dec 21:38
22d31a0
Compare
Choose a tag to compare
Update Python versions to test against

v0.8.0 -- Extensions and More Validators

03 Apr 05:05
Compare
Choose a tag to compare

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

29 Jan 04:47
Compare
Choose a tag to compare

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

25 Jan 04:44
Compare
Choose a tag to compare

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

21 Jan 18:09
Compare
Choose a tag to compare

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.