Welcome to Cerberus

Cerberus is an ISC Licensed validation tool for Python dictionaries.

Cerberus provides type checking and other base functionality out of the box and is designed to be easily extensible, allowing for easy custom validation. It has no dependancies and is thoroughly tested under Python 2.6, Python 2.7 and Python 3.3.

CERBERUS, n. The watch-dog of Hades, whose duty it was to guard the entrance; everybody, sooner or later, had to go there, and nobody wanted to carry off the entrance. -Ambrose Bierce, The Devil’s Dictionary

Usage

You define a validation schema and pass it to an instance of the Validator class:

>>> schema = {'name': {'type': 'string'}}
>>> v = Validator(schema)

Then you simply invoke the validate() or validate_update() methods to validate a dictionary against the schema. If validation succeeds, True is returned:

>>> document = {'name': 'john doe'}
>>> v.validate(document)
True

Alternatively, you can pass both the dictionary and the schema to the validate() method:

>>> v = Validator()
>>> v.validate(document, schema)
True

Which can be handy if your schema is changing thorough the life of the instance. False will be returned if validation fails. You can then access the errors() property to get a list of validation errors (see below).

Non-blocking

Unlike other validation tools, Cerberus will not halt and raise an exception on the first validation issue. The whole document will always be processed, and False will be returned if validation failed. You can then access the errors() method to obtain a list of issues.

>>> schema = {'name': {'type': 'string'}, 'age': {'type': 'integer', 'min': 10}}
>>> document = {'name': 1337, 'age': 5}
>>> v.validate(document, schema)
False
>>> v.errors
["min value for field 'age' is 10", "value of field 'name' must be of string type"]

You will still get SchemaError and ValidationError exceptions.

Allowing the unknown

By default only keys defined in the schema are allowed:

>>> schema = {'name': {'type': 'string', 'maxlength': 10}}
>>> v.validate({'name': 'john', 'sex': 'M'})
False
>>> v.errors
["unknown field 'sex'"]

However, you can allow unknown key/value pairs by setting the allow_unknown option to True:

>>> v.allow_unknown = True
>>> v.validate({'name': 'john', 'sex': 'M'})
True

allow_unknown can also be set at initialization:

>>> v = Validator(schema=schema, allow_unknown=True)
>>> v.validate({'name': 'john', 'sex': 'M'})
True

Custom validators

Cerberus makes custom validation simple. Suppose that in our specific and very peculiar use case a certain value can only be expressed as an odd integer, therefore we decide to add support for a new isodd rule to our validation schema:

>>> schema = {'oddity': {'isodd': True, 'type': 'integer'}}

This is how we would go to implement that:

from cerberus import Validator

class MyValidator(Validator):
    def _validate_isodd(self, isodd, field, value):
        if isodd and not bool(value & 1):
            self._error("Value for field '%s' must be an odd number" % field)

By subclassing Cerberus Validator class and adding the custom _validate_<rulename> function, we just enhanced Cerberus to suit our needs. The custom rule ìsodd is now available in our schema and, what really matters, we can validate it:

>>> v = MyValidator(schema)
>>> v.validate({'oddity': 10})
False
>>> v.errors
['Value for field 'oddity' must be an odd number']

>>> v.validate({'oddity': 9})
True

Adding new data-types

Cerberus supports and validates several standard data types (see type). You can add and validate your own data types. For example Eve (a tool for building and deploying proprietary REST Web APIs) supports a custom objectid type, which is used to validate that field values conform to the BSON/MongoDB ObjectId format.

You extend the supported set of data types by adding a _validate_type_<typename> method to your own Validator subclass. This snippet, directly from Eve source, shows how the objectid has been implemented:

def _validate_type_objectid(self, field, value):
   """ Enables validation for `objectid` schema attribute.

   :param field: field name.
   :param value: field value.
   """
   if not re.match('[a-f0-9]{24}', value):
       self._error(ERROR_BAD_TYPE % (field, 'ObjectId'))

New in version 0.0.2.

Validation Schema

A validation schema is a dictionary. Schema keys are the keys allowed in the target dictionary. Schema values express the rules that must be matched by the corresponding target values.

>>> schema = {'name': {'type': 'string', 'maxlength': 10}}

In the example above we define a target dictionary with only one key, name, which is expected to be a string not longer than 10 characters. Something like {'name': 'john doe'} would validate, while something like {'name': 'a very long string'} or {'name': 99} would not.

By definition all keys are optional unless the required rule is set for a key.

Validation Rules

The following rules are currently supported:

type

Data type allowed for the key value. Can be one of the following:
  • string
  • integer
  • float
  • boolean
  • datetime
  • dict
  • list

You can extend this list and support custom types, see Adding new data-types.

Changed in version 0.2.0: Added the float data type.

required

If True the key/value pair is mandatory and validation will fail when validate() is called. Validation will still succeed if the value is missing and validate_update() is called instead.:

>>> schema = {'name': {'required': True, 'type': 'string'}, 'age': {'type': 'integer'}}
>>> v = Validator(schema)
>>> document = {'age': 10}
>>> v.validate(document)
False
>>> v.errors
["required field(s) are missing: 'name'"]

>>> v.validate_update(document)
True

Note

String fields with empty values will still be validated, even when required is set to True. If you don’t want to accept empty values, see the empty rule.

readonly

If True the value is readonly. Validation will fail if this field is present in the target dictionary.

nullable

If True the field value can be set to None. It is essentially the functionality of the ignore_non_values parameter of the Validator Class, but allowing for more fine grained control down to the field level.

>>> schema = {'a_nullable_integer': {'nullable': True, 'type': 'integer'}, 'an_ingeger': {'type': 'integer'}}
>>> v = Validator(schema)

>>> v.validate({'a_nullable_integer': 3})
True
>>> v.validate({'a_nullable_integer': None})
True

>>> v.validate({'an_integer': 3})
True
>>> v.validate({'an_integer': None})
False
>>> v.errors
["value of field 'an_integer' must be of integer type"]

New in version 0.2.0.

minlength, maxlength

Minimum and maximum length allowed for string and list types.

min, max

Minimum and maximum value allowed for integer types.

allowed

Allowed values for string or list types. Validation will fail if target values are not included in the allowed list.:

>>> schema = {'role': {'type': 'list', 'allowed': ['agent', 'client', 'supplier']}}
>>> v = Validator(schema)
>>> v.validate({'role': ['agent', 'supplier']})
True

>>> v.validate({'role': ['intern']})
False
>>> v.errors
["unallowed values ['intern'] for field 'role'"]

>>> schema = {'role': {'type': 'string', 'allowed': ['agent', 'client', 'supplier']}}
>>> v = Validator(schema)
>>> v.validate({'role': 'supplier'})
True

>>> v.validate({'role': 'intern'})
False
>>> v.errors
["unallowed value 'intern' for field 'role'"]

empty

Only applies to string fields. If False validation will fail if the value is empty. Defaults to True.

>>> schema = {'name': {'type': 'string', 'empty': False}}
>>> document = {'name': ''}
>>> v.validate(document, schema)
False

>>> v.errors
["empty values not allowed for field 'name'"]

New in version 0.0.3.

items (dict)

Deprecated since version 0.0.3: Use schema instead.

When a dictionary, items defines the validation schema for items in a list type:

>>> schema = {'rows': {'type': 'list', 'items': {'sku': {'type': 'string'}, 'price': {'type': 'integer'}}}}
>>> document = {'rows': [{'sku': 'KT123', 'price': 100}]}
>>> v.validate(document, schema)
True

Note

The items (dict) rule is deprecated, and will be removed in a future release.

items (list)

When a list, items defines a list of values allowed in a list type of fixed length:

>>> schema = {'list_of_values': {'type': 'list', 'items': [{'type': 'string'}, {'type': 'integer'}]}}
>>> document = {'list_of_values': ['hello', 100]}
>>> v.validate(document, schema)
True

See schema rule below for dealing with arbitrary length list types.

schema

Validation schema for dict and list types. On dictionaries:

>>> schema = {'a_dict': {'type': 'dict', 'schema': {'address': {'type': 'string'}, 'city': {'type': 'string', 'required': True}}}}
>>> document = {'a_dict': {'address': 'my address', 'city': 'my town'}}
>>> v.validate(document, schema)
True

You can also use this rule to validate arbitrary length list items.

>>> schema = {'a_list': {'type': 'list', 'schema': {'type': 'integer'}}}
>>> document = {'a_list': [3, 4, 5]}
>>> v.validate(document, schema)
True

The schema rule on list types is also the prefered method for defining and validating a list of dictionaries.

>>> schema = {'rows': {'type': 'list', 'schema': {'type': 'dict', 'schema': {'sku': {'type': 'string'}, 'price': {'type': 'integer'}}}}}
>>> document = {'rows': [{'sku': 'KT123', 'price': 100}]}
>>> v.validate(document, schema)
True

Changed in version 0.0.3: Schema rule for list types of arbitrary length

Validator Class

class cerberus.Validator(schema=None, transparent_schema_rules=False, ignore_none_values=False, allow_unknown=False)

Validator class. Validates any Python dict against a validation schema, which is provided as an argument at class instantiation, or upon calling the validate() or validate_update() methods.

Parameters:
  • schema – optional validation schema.
  • transparent_schema_rules – if True unknown schema rules will be ignored (no SchemaError will be raised). Defaults to False. Useful you need to extend the schema grammar beyond Cerberus’ domain.
  • ignore_none_values – If True it will ignore None values for type checking. (no UnknowType error will be added). Defaults to False. Useful if your document is composed from function kwargs with defaults.
  • allow_unknown – if True unknown key/value pairs (not present in the schema) will be ignored, and validation will pass. Defaults to False, returning an ‘unknown field error’ un validation.

New in version 0.2.0: self.errors returns an empty list when validate() has not been called. Option so allow nullable field values. Option to allow unknown key/value pairs.

New in version 0.1.0: Option to ignore None values for type checking.

New in version 0.0.3: Support for transparent schema rules. Added new ‘empty’ rule for string fields.

New in version 0.0.2: Support for addition and validation of custom data types.

errors
Return type:a list of validation errors. Will be empty if no errors were found during. Resets after each call to validate() or validate_update().
validate(document, schema=None)

Validates a Python dictionary against a validation schema.

Parameters:
  • document – the dict to validate.
  • schema – the validation schema. Defaults to None. If not provided here, the schema must have been provided at class instantation.
Returns:

True if validation succeeds, False otherwise. Check the errors() property for a list of validation errors.

validate_update(document, schema=None)

Validates a Python dicitionary against a validation schema. The difference with validate() is that the required rule will be ignored here.

Parameters:schema – optional validation schema. Defaults to None. If not provided here, the schema must have been provided at class instantation.
Returns:True if validation succeeds, False otherwise. Check the errors() property for a list of validation errors.

Exceptions

class cerberus.SchemaError

Raised when the validation schema is missing, has the wrong format or contains errors.

class cerberus.ValidationError

Raised when the target dictionary is missing or has the wrong format

Installation

Cerberus is on PyPI so all you need to do is:

pip install cerberus

Testing

https://secure.travis-ci.org/nicolaiarocci/cerberus.png?branch=master
>>> python setup.py test

Source Code

Source code is available at GitHub.