Schemable is a schema parsing and validation library that let's you define schemas simply using dictionaries, lists, types, and callables.
- Project: https://github.com/dgilland/schemable
- Documentation: https://schemable.readthedocs.io
- PyPI: https://pypi.python.org/pypi/schemable/
- TravisCI: https://travis-ci.org/dgilland/schemable
- Simple schema definitions using
dict
,list
, andtype
objects - Complex schema definitions using
Any
,All
,As
, and predicates - Detailed validation error messages
- Partial data loading on validation failure
- Strict and non-strict parsing modes
- Python 3.4+
Install using pip:
pip install schemable
Define a schema using dict
and list
objects:
from schemable import Schema, All, Any, As, Optional, SchemaError
user_schema = Schema({
'name': str,
'email': All(str, lambda email: len(email) > 3 and '@' in email),
'active': bool,
'settings': {
Optional('theme'): str,
Optional('language', default='en'): str,
Optional('volume'): int,
str: str
},
'aliases': [str],
'phone': All(str,
As(lambda phone: ''.join(filter(str.isdigit, phone))),
lambda phone: 10 <= len(phone) <= 15),
'addresses': [{
'street_addr1': str,
Optional('street_addr2', default=None): Any(str, None),
'city': str,
'state': str,
'country': str,
'zip_code': str
}]
})
Then validate and load by passing data to user_schema()
:
# Fail!
result = user_schema({
'name': 'Bob Smith',
'email': 'bob.example.com',
'active': 1,
'settings': {
'theme': False,
'extra_setting1': 'val1',
'extra_setting2': True
},
'phone': 1234567890,
'addresses': [
{'street_addr1': '123 Lane',
'city': 'City',
'state': 'ST',
'country': 'US',
'zip_code': 11000}
]
})
print(result)
# SchemaResult(
# data={'name': 'Bob Smith',
# 'settings': {'extra_setting1': 'val1',
# 'language': 'en'}
# 'addresses': [{'street_addr1': '123 Lane',
# 'city': 'City',
# 'state': 'ST',
# 'country': 'US',
# 'street_addr2': None}]},
# errors={'email': "bad value: <lambda>('bob.example.com') should evaluate to True",
# 'active': 'bad value: type error, expected bool but found int',
# 'settings': {'theme': 'bad value: type error, expected str but found bool',
# 'extra_setting2': 'bad value: type error, expected str but found bool'},
# 'phone': 'bad value: type error, expected str but found int',
# 'addresses': {0: {'zip_code': 'bad value: type error, expected str but found int'}},
# 'aliases': 'missing required key'})
# Fail!
result = user_schema({
'name': 'Bob Smith',
'email': 'bob@example.com',
'active': True,
'settings': {
'theme': False,
'extra_setting1': 'val1',
'extra_setting2': 'val2'
},
'phone': '123-456-789',
'addresses': [
{'street_addr1': '123 Lane',
'city': 'City',
'state': 'ST',
'country': 'US',
'zip_code': '11000'}
]
})
print(result)
# SchemaResult(
# data={'name': 'Bob Smith',
# 'email': 'bob@example.com',
# 'active': True,
# 'settings': {'extra_setting1': 'val1',
# 'extra_setting2': 'val2',
# 'language': 'en'},
# 'addresses': [{'street_addr1': '123 Lane',
# 'city': 'City',
# 'state': 'ST',
# 'country': 'US',
# 'zip_code': '11000',
# 'street_addr2': None}]},
# errors={'settings': {'theme': 'bad value: type error, expected str but found bool'},
# 'phone': "bad value: <lambda>('123456789') should evaluate to True",
# 'aliases': 'missing required key'})
Or can raise an exception on validation failure instead of returning results:
# Fail strictly!
try:
user_schema({
'name': 'Bob Smith',
'email': 'bob@example.com',
'active': True,
'settings': {
'theme': False,
'extra_setting1': 'val1',
'extra_setting2': 'val2'
},
'phone': '123-456-789',
'addresses': [
{'street_addr1': '123 Lane',
'city': 'City',
'state': 'ST',
'country': 'US',
'zip_code': '11000'}
]
}, strict=True)
except SchemaError as exc:
print(exc)
# Schema validation failed: \
# {'settings': {'theme': 'bad value: type error, expected str but found bool'}, \
# 'phone': "bad value: <lambda>('123456789') should evaluate to True", \
# 'aliases': 'missing required key'}
Access the parsed data after successful validation:
# Pass!
result = user_schema({
'name': 'Bob Smith',
'email': 'bob@example.com',
'active': True,
'settings': {
'theme': 'dark',
'extra_setting1': 'val1',
'extra_setting2': 'val2'
},
'phone': '123-456-7890',
'aliases': [],
'addresses': [
{'street_addr1': '123 Lane',
'city': 'City',
'state': 'ST',
'country': 'US',
'zip_code': '11000'}
]
})
print(result)
# SchemaResult(
# data={'name': 'Bob Smith',
# 'email': 'bob@example.com',
# 'active': True,
# 'settings': {'theme': 'dark',
# 'extra_setting1': 'val1',
# 'extra_setting2': 'val2',
# 'language': 'en'},
# 'phone': '1234567890',
# 'aliases': [],
# 'addresses': [{'street_addr1': '123 Lane',
# 'city': 'City',
# 'state': 'ST',
# 'country': 'US',
# 'zip_code': '11000',
# 'street_addr2': None}]},
# errors={})
For more details, please see the full documentation at https://schemable.readthedocs.io.