Lightweight, extensible data validation library for Python

Overview

Cerberus Latest version on PyPI

Build status Python versions Black code style

Cerberus is a lightweight and extensible data validation library for Python.

>>> v = Validator({'name': {'type': 'string'}})
>>> v.validate({'name': 'john doe'})
True

Features

Cerberus provides type checking and other base functionality out of the box and is designed to be non-blocking and easily and widely extensible, allowing for custom validation. It has no dependencies, but has the potential to become yours.

Versioning & Interpreter support

The Cerberus 1.x versions can be used with Python 2 while version 2.0 and later rely on Python 3 features.

Starting with Cerberus 1.2, it is maintained according to semantic versioning. So, a major release sheds off the old and defines a space for the new, minor releases ship further new features and improvements (you now the drill, new bugs are inevitable too), and micro releases polish a definite amount of features to glory.

We intend to test Cerberus against all CPython interpreters at least until half a year after their end of life and against the most recent PyPy interpreter as a requirement for a release. If you still need to use it with a potential security hole in your setup, it should most probably work with the latest minor version branch from the time when the interpreter was still tested. Subsequent minor versions have good chances as well. In any case, you are advised to run the contributed test suite on your target system.

Funding

Cerberus is an open source, collaboratively funded project. If you run a business and are using Cerberus in a revenue-generating product, it would make business sense to sponsor its development: it ensures the project that your product relies on stays healthy and actively maintained. Individual users are also welcome to make a recurring pledge or a one time donation if Cerberus has helped you in your work or personal projects.

Every single sign-up makes a significant impact towards making Eve possible. To learn more, check out our funding page.

Documentation

Complete documentation is available at http://docs.python-cerberus.org

Installation

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

$ pip install cerberus

Testing

Just run:

$ python setup.py test

Or you can use tox to run the tests under all supported Python versions. Make sure the required python versions are installed and run:

$ pip install tox  # first time only
$ tox

Contributing

Please see the Contribution Guidelines.

Copyright

Cerberus is an open source project by Nicola Iarocci. See the license file for more information.

Comments
  • `readonly` conflicts with `default` (and `rule_filter`)

    `readonly` conflicts with `default` (and `rule_filter`)

    This allows using default and readonly on the same field. See #268 for details.

    Furthermore, this PR introduces a new feature called rule_filter to solve #268 in an (in my opinion) elegant way. I'm not sure if this feature will be ever used externally, but just in case I wrote some documentation for it. Briefly speaking, it allows to do the following:

    >>> schema = {'name': {'type': 'string', 'maxlength': 10}}
    >>> v = Validator(schema, rule_filter=lambda f: f != 'maxlength')
    >>> v.validate({'name': 'Johanna-Maria'}, schema)
    True
    
    enhancement 
    opened by dkellner 25
  • Type coercion validator

    Type coercion validator

    By adding a coerce: <some callable> validator to a schema the return value of the callable will be used as the value to validate against in the document. This overwrite the value in the document so requires that you make a copy of the document before passing it to the validator if you don't want your original document changed.

    This isn't fool proof as it only catches TypeError and ValueError in coercion validator but it is incredibly handy to have for sanitizing and validating HTTP request data.

    opened by brettatoms 24
  • Required if another field has value of

    Required if another field has value of

    Hi,

    this issue is the same as https://github.com/nicolaiarocci/cerberus/issues/121 but the answer is not satisfactory.

    I would like to have field "layer" required only if filed "type" has value "folder", so this would be the result: doc = {"type": "folder", "layer": "a"} v.validate(doc, schema) True

    doc = {"type": "category"} v.validate(doc, schema) True

    doc = {"type": "category", "layer": "a"} print v.validate(doc, schema) False

    doc = {"type": "folder"} v.validate(doc, schema) False

    from the issue #121 funkyfuture wrote: schema = {'oneof' = [{'product_type': {'regex': '^car$'}, 'color': {'required': True}}, {'product_type': {'regex': '^bike$'}}]}

    but this is not even a correct python code. How should i define schema for such case ?

    opened by mczerski 22
  • Adding support for Decimal type (Decimal module)

    Adding support for Decimal type (Decimal module)

    This PR has the goal to provide support to validate decimal data type.

    This way allows checking whether the number in the request is parsable by the decimal module. Note: this is to provide support for the new decimal type in mongodb.

    opened by Amedeo91 21
  • Keep a reference to the current document, 'rename' and 'remove_unknown' options

    Keep a reference to the current document, 'rename' and 'remove_unknown' options

    This relates to #95 , where no reference is kept to the document being validated and hence not being able to change or remove fields. This commit maintains references and adds a current property to the validator, pointing to the current document and making it available to custom validators.

    opened by misja 21
  • Validation of lists

    Validation of lists

    Hi.

    I want to ask if currently cerberus allow us to validate lists? I may have a simple input doc in the list form:

    [{"id": 1}, {"id": 2}]

    Is it possible to validate it?

    I know that I may wrap this in a dict and use the standard validation, but I was wandering if it's possible without dict.

    Thx.

    opened by botzill 18
  • Feature anyof

    Feature anyof

    Adds an 'anyof' rule that will allow a list of definitions to be given. Currently, all rules in a definition are checked, so a rule is a set of constraints that are AND'ed together. The 'anyof' key allows constraints to be OR'ed. This should work transparently will all existing rules and any user defined validators.

    Simple example, taken from unit test

    # prop1 must be either a number between 0 and 10
    schema = {'prop1':  {'min': 0, 'max': 10}}
    doc = {'prop1': 5}
    
    self.assertSuccess(doc, schema)
    
    # prop1 must be either a number between 0 and 10 or 100 and 110
    schema = {'prop1':
                      {'anyof':
                       [{'min': 0, 'max': 10}, {'min': 100, 'max': 110}]}}
    doc = {'prop1': 105}
    
    self.assertSuccess(doc, schema)
    
    # prop1 must be either a number between 0 and 10 or 100 and 110
    schema = {'prop1':
                      {'anyof':
                       [{'min': 0, 'max': 10}, {'min': 100, 'max': 110}]}}
    doc = {'prop1': 50}
    
    self.assertValidationError(doc, schema)
    
    

    This also satisfies #108. See the unit test for the syntax.

    opened by CD3 18
  • Problem with required and dependencies

    Problem with required and dependencies

    Used Cerberus version 1.0.1 installed with pip

    • I consulted these documentations:
      • [ Validation Rules] http://docs.python-cerberus.org/en/stable/validation-rules.html

    Support request / Bug report

    According to the docs, the following program should validate successfully since the auth-key field is required only when the auth field is wep or wpa.

    
    import cerberus
    
    schema = {
        'auth' : {
            'type':'string',
            'required':True,
            'allowed':['open','wep','wpa']
        },
        'auth-key' : {
            'type':'string',
            'required':True,
            'dependencies': {'auth': ['wep', 'wpa']}
        }
    }
    
    v = cerberus.Validator(schema)
    print v.validate({'auth':'open'})
    print v.errors
    

    The output of the program is the following:

    False
    {'auth-key': ['required field']}
    

    Is this a bug ?

    opened by evga 16
  • Proposal: option to purge unknown fields on validation

    Proposal: option to purge unknown fields on validation

    I have the need to apart from validating the data to also remove unknown fields. I couldn't see an easy way in _validate to get a direct reference to the document element being parsed so for now I subclass Validator and do a clean post validation based on the errors dict, see this gist. I was wondering, has this been discussed before, would it be something to include, and how to best handle it via _validate?

    opened by misja 15
  • Schema file not working anymore with Cerberus 1.3

    Schema file not working anymore with Cerberus 1.3

    Used Cerberus version / latest commit: Cerberus 1.3 / Python 3.5.2

    • [ ] I have the capacity to improve the docs when my problem is solved.

    • [ ] I have the capacity to submit a patch when a bug is identified.

    • [ ] My question does not concern a practical use-case that I can't figure out to solve.


    Use-case abstract

    Since Cerberus 1.3, keyschema and valueschema are deprecated and should still work, but I get an error when using them.

    The error is gone when using the new keys keysrules and valuesrules.

    Here is my schema :

    requests:
      type: dict
      keyschema:
        type: string
      valueschema:
        type: dict
        schema:
          aggs:
            type: dict
            keyschema:
              type: string
            valueschema:
              type: dict
    

    My Python code :

    #!/usr/bin/env python3
    
    from yaml import load, load_all
    from cerberus import Validator
    
    schemafile = "schema.yml"
    
    with open(schemafile, "r") as f:
        schema = load(f)
    
    v = Validator(schema)
    

    And the Python error :

    
    Traceback (most recent call last):
      File "./test.py", line 11, in <module>
        v = Validator(schema)
      File "/usr/local/lib/python3.5/dist-packages/cerberus/validator.py", line 181, in __init__
        self.schema = kwargs.get('schema', None)
      File "/usr/local/lib/python3.5/dist-packages/cerberus/validator.py", line 562, in schema
        self._schema = DefinitionSchema(self, schema)
      File "/usr/local/lib/python3.5/dist-packages/cerberus/schema.py", line 76, in __init__
        self.validate(schema)
      File "/usr/local/lib/python3.5/dist-packages/cerberus/schema.py", line 247, in validate
        self._validate(schema)
      File "/usr/local/lib/python3.5/dist-packages/cerberus/schema.py", line 263, in _validate
        raise SchemaError(self.schema_validator.errors)
    cerberus.schema.SchemaError: {'requests': [{'valuesrules': [{'schema': ['no definitions validate', {'anyof definition 0': [{'aggs': [{'valueschema': ['unknown rule'], 'keyschema': ['unknown rule']}]}], 'anyof definition 1': [{'aggs': ['unknown rule']}]}]}]}]}
    

    Bug report / Feature request

    opened by fdeschamps 14
  • Error in get_rule_handler after updating to 1.2

    Error in get_rule_handler after updating to 1.2

    After updating from 1.1 to 1.2 my tests are failing with exception:

    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:877: in validate
        self.__validate_definitions(definitions, field)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:940: in __validate_definitions
        result = validate_rule(rule)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:922: in validate_rule
        return validator(definitions.get(rule, None), field, value)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:1236: in _validate_schema
        self.__validate_schema_mapping(field, schema, value)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:1247: in __validate_schema_mapping
        if not validator(value, update=self.update, normalize=False):
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:877: in validate
        self.__validate_definitions(definitions, field)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:940: in __validate_definitions
        result = validate_rule(rule)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:922: in validate_rule
        return validator(definitions.get(rule, None), field, value)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:1234: in _validate_schema
        self.__validate_schema_sequence(field, schema, value)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:1259: in __validate_schema_sequence
        update=self.update, normalize=False)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:877: in validate
        self.__validate_definitions(definitions, field)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:940: in __validate_definitions
        result = validate_rule(rule)
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:921: in validate_rule
        validator = self.__get_rule_handler('validate', rule)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <cerberus.validator.Validator object at 0x7f94a6315a58>
    domain = 'validate', rule = 'id'
    
        def __get_rule_handler(self, domain, rule):
            methodname = '_{0}_{1}'.format(domain, rule.replace(' ', '_'))
            result = getattr(self, methodname, None)
            if result is None:
                raise RuntimeError("There's no handler for '{}' in the '{}' "
    >                              "domain.".format(rule, domain))
    E           RuntimeError: There's no handler for 'id' in the 'validate' domain.
    
    /usr/local/lib/python3.6/site-packages/cerberus/validator.py:338: RuntimeError```
    
    I don't know if it has something to do with my schemes. I have only one "id":
    "id": {
            "required": True,
            "type": "integer"
        } 
    opened by Luckjanov 14
  • Dependencies not being honored?

    Dependencies not being honored?

    I am writing a validation schema that I think is correct, but is not honoring the mapping on the dependencies

    question_schema = {
        'question': {
            'type': 'dict',
            'schema': {
                'type': {
                    'required': True,
                    'type': 'string',
                    'allowed': ['free_answer', 'single_choice', 'multiple_choice']
                },
                'options': {
                    'required': True,
                    'dependencies': {
                        'type': ['single_choice', 'multiple_choice']
                    }
                }
            }
        }
    }
    
    v = Validator(question_schema)
    v.validate({'feature': {'type': 'free_answer'}})     # Does not validate, claiming 'options' is required, but should be True
    v.validate({'feature': {'type': 'single_choice', 'options': 'a'}})   # successfully validates
    

    Used Cerberus version / latest commit: 1.3.4

    opened by flixman 0
  • Feature #444 - Document level validation

    Feature #444 - Document level validation

    With this PR you can create document level validations - i.e. validations not attached to a field, but to the document so that it can consider multiple fields at once.

    For example, a drink order is invalid if 1) it includes an alcoholic beverage and 2) the customer's age is below the allowed drinking age. To accomplish this with document level validations:

        class MyValidator(Validator):
            def _validate_document_allowed_drinking_age(self, allowed_drinking_age):
                """ Ensure only those of allowed drinking age or older can order alcohol
    
                The rule's arguments are validated against this schema:
                {'type': 'integer'}
                """
                if not allowed_drinking_age:
                    return
                is_valid = True
                beverage = self.document.get('beverage')
                age = self.document.get('customer_age', 0)
                if beverage in ['beer', 'wine']:
                    is_valid = age >= allowed_drinking_age
                if not is_valid:
                    self._error('_document', f'Invalid order: Cannot order {beverage} at age {age} (must be {allowed_drinking_age} or over)')
    
    
    
    >>> schema = {'beverage': {'type': 'string', 'allowed': ['beer', 'wine', 'water', 'soda']},'customer_age': {'type': 'integer'}}
    >>> v = MyValidator(schema, document_validations={'allowed_drinking_age': 21})
    >>> v.validate({'beverage': 'beer', 'customer_age': 22})
    True
    >>> v.validate({'beverage': 'soda', 'customer_age': 10})
    True
    >>> v.validate({'beverage': 'beer', 'customer_age': 12})
    False
    >>>v.errors
    {'_document': ['Invalid order: Cannot order beer at age 12 (must be 21 or over)']}
    
    opened by biscuit314 1
  • Conditional validation for empty parameter

    Conditional validation for empty parameter

    opened by qwertyuiop-s 0
  • Unexpected normalization behavior with anyof_schema

    Unexpected normalization behavior with anyof_schema

    Used Cerberus version / latest commit: 1.3.4

    • [X] I have the capacity to improve the docs when my problem is solved.

    • [ ] I have the capacity to submit a patch when a bug is identified.

    • [X] My question does not concern a practical use-case that I can't figure out to solve.


    Use-case abstract

    I want to normalize a dictionary inside a dictionary with default values. If I validate against a single schema I get the expected normalized dictionary. When I validate against two schemas with anyof, the behaviour changes.


    Bug report

    The following code validates the dictionary {'a_dict': {}} with the schema A and the schema any of A or B. The problem is that in the second case the dictionary is not being normalized as expected.

    Running the code:

    from cerberus import Validator
    
    
    A = {'key': {'type': 'string', 'required': False, 'default': 'X', }}
    B = {'key': {'type': 'integer', 'required': False, 'default': 1, }}
    
    v1 = Validator({
        'a_dict': {
            'type': 'dict',
            'schema': A,
        },
    })
    
    v2 = Validator({
        'a_dict': {
            'type': 'dict',
            'anyof_schema': [A, B]
        },
    })
    
    x = {'a_dict': {}}
    
    print(v1.validated(x))
    print(v2.validated(x))
    

    the result is

    {'a_dict': {'key': 'X'}}
    {'a_dict': {}}
    

    I would expect the result to be

    {'a_dict': {'key': 'X'}}
    {'a_dict': {'key': 'X'}}
    

    I am using Python 3.9 and Cerberus 1.3.4

    opened by gtarabat 0
  • Improve docs for conditionally required field

    Improve docs for conditionally required field

    I'm trying to require key only when another key has a certain value.

    I'm sure it is possible but I believe the docs can be improved or an example can be provided.

    I asked on SO but didn't get any answers.

    https://stackoverflow.com/questions/72898158/cerberus-validation-and-conditionally-require-a-field

    opened by Siecje 0
  • Use of __double_leading_underscore preventing extending

    Use of __double_leading_underscore preventing extending

    Used Cerberus version / latest commit: 1.3.4

    • [x] I have the capacity to improve the docs when my problem is solved.

    • [x] I have the capacity to submit a patch when a bug is identified.

    • [x] My question does not concern a practical use-case that I can't figure out to solve.


    Use-case abstract

    To allow extending some core features of cerberus, __double_leading_underscore methods should be avoided if possible. Currently there are many e.g.:

    __normalize_sequence_per_items
    __normalize_containers
    __normalize_mapping
    

    And these call each other, meaning to replace some functionality of __normalize_sequence_per_items, you have to replace the normalized and validate functions that begin the call chain.

    In my case, I'd like to extend __normalize_sequence_per_items to handle the if len(rules) != len(values): case for my specific validator.


    Bug report / Feature request

    Use _single_leading_underscore to allow for extending in child classes. I understand that __ was likely used to allow cerberus versions to change this underlying behavior without worrying about breaking people's implementations, but it severely limits how cerberus can be extended in its current state.

    I propose switching some higher level method to _single_underscore and keeping them consistent between releases while leaving lower level methods as __double_underscore. In the above example, perhaps:

    __normalize_sequence_per_items
    _normalize_containers
    _normalize_mapping
    
    opened by dkarp0 0
Owner
eve
REST API framework designed for human beings
eve
Lightweight data validation and adaptation Python library.

Valideer Lightweight data validation and adaptation library for Python. At a Glance: Supports both validation (check if a value is valid) and adaptati

Podio 258 Nov 22, 2022
CONTRIBUTIONS ONLY: Voluptuous, despite the name, is a Python data validation library.

CONTRIBUTIONS ONLY What does this mean? I do not have time to fix issues myself. The only way fixes or new features will be added is by people submitt

Alec Thomas 1.8k Dec 31, 2022
Data parsing and validation using Python type hints

pydantic Data validation and settings management using Python type hinting. Fast and extensible, pydantic plays nicely with your linters/IDE/brain. De

Samuel Colvin 12.1k Jan 6, 2023
Python Data Validation for Humans™.

validators Python data validation for Humans. Python has all kinds of data validation tools, but every one of them seems to require defining a schema

Konsta Vesterinen 670 Jan 9, 2023
Typical: Fast, simple, & correct data-validation using Python 3 typing.

typical: Python's Typing Toolkit Introduction Typical is a library devoted to runtime analysis, inference, validation, and enforcement of Python types

Sean 171 Jan 2, 2023
Schema validation just got Pythonic

Schema validation just got Pythonic schema is a library for validating Python data structures, such as those obtained from config-files, forms, extern

Vladimir Keleshev 2.7k Jan 6, 2023
Schema validation for Xarray objects

xarray-schema Schema validation for Xarray installation This package is in the early stages of development. Install it from source: pip install git+gi

carbonplan 22 Oct 31, 2022
Python Data Structures for Humans™.

Schematics Python Data Structures for Humans™. About Project documentation: https://schematics.readthedocs.io/en/latest/ Schematics is a Python librar

Schematics 2.5k Dec 28, 2022
An(other) implementation of JSON Schema for Python

jsonschema jsonschema is an implementation of JSON Schema for Python. >>> from jsonschema import validate >>> # A sample schema, like what we'd get f

Julian Berman 4k Jan 4, 2023
Param: Make your Python code clearer and more reliable by declaring Parameters

Param Param is a library providing Parameters: Python attributes extended to have features such as type and range checking, dynamically generated valu

HoloViz 304 Jan 7, 2023
A simple, fast, extensible python library for data validation.

Validr A simple, fast, extensible python library for data validation. Simple and readable schema 10X faster than jsonschema, 40X faster than schematic

kk 209 Sep 19, 2022
Lightweight data validation and adaptation Python library.

Valideer Lightweight data validation and adaptation library for Python. At a Glance: Supports both validation (check if a value is valid) and adaptati

Podio 258 Nov 22, 2022
barely is a lightweight, but highly extensible static site generator written in pure python.

barely is a lightweight, but highly extensible static site generator. Explore the docs » Quickstart · See available Plugins · Report Bug · Request Fea

null 40 Dec 1, 2022
CONTRIBUTIONS ONLY: Voluptuous, despite the name, is a Python data validation library.

CONTRIBUTIONS ONLY What does this mean? I do not have time to fix issues myself. The only way fixes or new features will be added is by people submitt

Alec Thomas 1.8k Dec 31, 2022
A flexible forms validation and rendering library for Python.

WTForms WTForms is a flexible forms validation and rendering library for Python web development. It can work with whatever web framework and template

WTForms 1.4k Dec 31, 2022
App and Python library for parsing, writing, and validation of the STAND013 file format.

python-stand013 python-stand013 is a Python app and library for parsing, writing, and validation of the STAND013 file format. Features The following i

Oda 3 Nov 9, 2022
ckan 3.6k Dec 27, 2022
Data parsing and validation using Python type hints

pydantic Data validation and settings management using Python type hinting. Fast and extensible, pydantic plays nicely with your linters/IDE/brain. De

Samuel Colvin 12.1k Jan 5, 2023
Typical: Fast, simple, & correct data-validation using Python 3 typing.

typical: Python's Typing Toolkit Introduction Typical is a library devoted to runtime analysis, inference, validation, and enforcement of Python types

Sean 170 Dec 26, 2022
Data parsing and validation using Python type hints

pydantic Data validation and settings management using Python type hinting. Fast and extensible, pydantic plays nicely with your linters/IDE/brain. De

Samuel Colvin 12.1k Jan 6, 2023