Validate Python dictionaries like JSON schema
Project description
Usage
A schemadict is a regular Python dictionary which specifies the type and format of values for some given key. To check if a test dictionary is conform with the expected schema, schemadict provides the validate() method. If the test dictionary is ill-defined, an error will be thrown, otherwise None is returned.
Examples
Basic usage
>>> from schemadict import schemadict
>>> schema = schemadict({
... 'name': {
... 'type': str,
... 'min_len': 3,
... 'max_len': 12,
... },
... 'age': {
... 'type': int,
... '>=': 0,
... '<': 150,
... },
... })
>>>
>>> testdict = {'name': 'Neil', 'age': 55}
>>> schema.validate(testdict)
>>>
>>> testdict = {'name': 'Neil', 'age': -12}
>>> schema.validate(testdict)
Traceback (most recent call last):
...
ValueError: 'age' too small: expected >= 0, but was -12
>>>
>>> testdict = {'name': 'Neil', 'age': '55'}
>>> schema.validate(testdict)
Traceback (most recent call last):
...
TypeError: unexpected type for 'age': expected <class 'int'>, but was <class 'str'>
>>>
Nested schemadict
It is possible to check individual item in a list. For instance, in the following example we check if each item (of type str) looks like a valid IPv4 address. How each item should look like can be specified with the item_schema keyword.
>>> schema = schemadict({
... 'ip_addrs': {
... 'type': list,
... 'item_schema': {
... 'type': str,
... 'regex': r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$',
... },
... },
... })
>>>
>>>
>>> schema.validate({'ip_addrs': ['127.0.0.1', '192.168.1.1']}) # Valid
>>> schema.validate({'ip_addrs': ['127.0.0.1', '192.168.1.1', '1234.5678']}) # Last item invalid
Traceback (most recent call last):
...
ValueError: regex mismatch for 'ip_addrs': expected pattern '^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$', got '1234.5678'
>>>
Items in a list (or tuple) may themselves be dictionaries which can be described with schemadicts. In this case, we use the keyword item_schemadict as illustrated in the following example.
>>> schema_city = schemadict({
... 'name': {
... 'type': str
... },
... 'population': {
... 'type': int,
... '>=': 0,
... },
... })
>>>
>>> schema_country = schemadict({
... 'name': {'type': str},
... 'cities': {
... 'type': list,
... 'item_type': dict,
... 'item_schemadict': schema_city,
... },
... })
>>>
>>> test_country = {
... 'name': 'Neverland',
... 'cities': [
... {'name': 'Faketown', 'population': 3},
... {'name': 'Evergreen', 'population': True},
... ],
... }
>>>
>>> schema_country.validate(test_country)
Traceback (most recent call last):
...
TypeError: unexpected type for 'population': expected <class 'int'>, but was <class 'bool'>
>>>
Custom validation functions
Each type (int, bool, str, etc.) defines its own set of validation keywords and corresponding test functions. The dictionary STANDARD_VALIDATORS provided by the schemadict module contains the default validation functions for the Python’s built-in types. However, it is also possible to modify or extend this dictionary with custom validation functions.
>>> from schemadict import schemadict, STANDARD_VALIDATORS
>>> # Add a custom validation function
>>> def is_divisible(key, value, comp_value, _):
... if value % comp_value != 0:
... raise ValueError(f"{key!r} is not divisible by {comp_value}")
...
...
...
>>>
>>> # Update the standard validator dictionary
>>> my_validators = STANDARD_VALIDATORS
>>> my_validators[int]['%'] = is_divisible
>>> # Register the updated validator dictionary in the new schemadict instance
>>> s = schemadict({'my_num': {'type': int, '%': 3}}, validators=my_validators)
>>> s.validate({'my_num': 33})
>>> s.validate({'my_num': 4})
Traceback (most recent call last):
...
ValueError: 'my_num' is not divisible by 3
>>>
It is also possible to define custom types and custom test functions as shown in the following example.
>>> from schemadict import schemadict, STANDARD_VALIDATORS
>>> class MyOcean:
... has_dolphins = True
... has_plastic = False
...
>>>
>>> def has_dolphins(key, value, comp_value, _):
... if getattr(value, 'has_dolphins') is not comp_value:
... raise ValueError(f"{key!r} does not have dolphins")
...
>>>
>>> my_validators = STANDARD_VALIDATORS
>>> my_validators.update({MyOcean: {'has_dolphins': has_dolphins}})
>>>
>>> schema_ocean = schemadict(
... {'ocean': {'type': MyOcean, 'has_dolphins': True}},
... validators=my_validators,
... )
>>>
>>> ocean1 = MyOcean()
>>> schema_ocean.validate({'ocean': ocean1})
>>>
>>> ocean2 = MyOcean()
>>> ocean2.has_dolphins = False
>>> schema_ocean.validate({'ocean': ocean2})
Traceback (most recent call last):
...
ValueError: 'ocean' does not have dolphins
Full documentation: https://schemadict.readthedocs.io/
Features
What schemadict offers:
Built-in support for Python’s “primitive types”
Specify required and optional keys
Validate nested schemas
Add custom validation functions to built-in types
Add custom validation functions to custom types
Support for Regex checks of strings
Features currently in development
Metaschema validation
Lazy validation and summary of all errors
Allow schema variations: schmea 1 OR schema 2
Installation
Schemadict is available on PyPI and may simply be installed with
pip install schemadict
Idea
Schemadict is loosely inspired by JSON schema and jsonschema, a JSON schema validator for Python.
License
License: Apache-2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for schemadict-0.0.12-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 102d061831769d19948e675d9aabd1c1741449bce6eb82dc3f455fa7f2b0a255 |
|
MD5 | 90e507d4c2c3402348976cbac6510769 |
|
BLAKE2b-256 | 1428c27e3112a6a521f21f7996570379018f62a36f37270891965932fd92c1d6 |