Quickstart
Installation
CleanChausie requires Python 3.8+.
To install, run python3 -m pip install cleanchausie
.
Declaring a Schema
Declarative schemas inherit from cleanchausie.Schema
. In its simplest form:
import datetime
from typing import Optional
from cleanchausie import Schema, clean, serialize
class JobApplication(Schema):
name: str
middle_initial: Optional[str] = None
referrer: Optional[str]
timestamp: datetime.datetime
external_data = {
'name': 'John Doe',
'referrer': None,
'timestamp': '2020-01-01T00:00:00Z',
}
validation_result = clean(JobApplication, external_data)
print(serialize(validation_result))
"""
{
'name': 'John Doe',
'middle_initial': None,
'referrer': None,
'timestamp': '2020-01-01T00:00:00+00:00'
}
"""
What's going on here? Let's break it down:
- Inheriting from
Schema
gives us a few things:- A
clean
classmethod, which takes in a dictionary and returns aSchema
instance if validation passes, or aValidationError
if validation fails. - A
serialize
method, which returns a dictionary representation of the schema instance.
- A
name
is annotated asstr
. CleanChausie automatically turns this into aStringField
, which will only accept string values.middle_initial
is an not required, and if omitted is set toNone
.referrer
is required, but is also nullable. Omitting it will result in a validation error, but an explicitNone
is completely valid.timestamp
is our first non-string field. It's adatetime
and is required. Datetime-ey strings are turned intodatetime
objects.
If validation fails, instead of returning an instance of JobApplication
, we
get a ValidationError
instance instead.
external_data = {
'name': 5,
'timestamp': 'The first monday after Jan 1 1970',
}
validation_result = clean(JobApplication, external_data)
print(serialize(validation_result))
"""
{
'errors': [
{
'field': ('timestamp',),
'msg': "Could not parse datetime from 'The first monday after Jan 1 1970'"
},
{'field': ('referrer',), 'msg': 'This field is required.'},
{'field': ('name',), 'msg': "Expected a string, got 'int'."}
]
}
"""
But why CleanChausie?
Types
CleanChausie operates on/with type-checked objects that have good IDE/autocomplete support. Simple fields can be declared with just annotations.
Errors are returned instead of raised, which means mypy
will help you
catch validation errors.
Composable
Fields and field validation logic are composable and reusable. The declarative
Schema
class is a wrapper around a more functional core, which leans into
composition over inheritance. It's easy to write and reuse custom fields which
compose and extend existing fields.
Context
Validation supports (but does not require) passing around an explicit context
to any field validation function that requests it. It's only used within
validation logic, is not stored with validated data. Contexts are commonly used
to avoid global state, or for explicit session management on database lookups.
Nullable vs Omitted
Presence validation and value validation are treated as distinct first-class
citizens. Fields can be required, required and nullable, omittable (with an
omitted
singleton default), or omittable with a different default value.
Cleanchausie understands Union[OMITTED, str]
annotations, and can
automatically parse all the above scenarios.
Intra-schema dependencies
Fields within a schema can depend on the validated value of other fields in the same schema. Validated values are passed to dependent fields as args (using dependency injection), and the field validation order is handled automatically.