Overview of Trafaret
masteraiohttp via asynchronous checking. Key features include a shortcut syntax for building complex validators and the ability to generate Trafarets from JSON (via trafaret_schema).repository·master·Indexed 41 days ago
https://github.com/deepwalker/trafaretA Python library for data validation and transformation designed for handling foreign data and configurations. It supports synchronous and asynchronous (aiohttp) workflows, providing a type-safe approach to validate and convert data structures using checkers like Dict, String, Float, and ToBool. It includes utilities for handling nested keys via trafaret.constructor and detailed error reporting through DataError.
aiohttp via asynchronous checking. Key features include a shortcut syntax for building complex validators and the ability to generate Trafarets from JSON (via trafaret_schema).To bridge the gap between JavaScript's camelCase and Python's snake_case, use t.Key within a t.Dict. This allows you to define the expected input key while renaming it to a preferred internal key during the .check() process.
You can use the >> operator or the to_name argument.
# Using the >> operator
t.Dict({t.Key('userNameFirst') >> 'first_name': t.String})
# Using the to_name argument
t.Dict({t.Key('userNameFirst', to_name='first_name'): t.String})You can combine multiple checkers so that the input is considered valid if any one of the checkers succeeds. The most common way to do this is using the bitwise OR operator |.
# Using the | operator
(t.Int | t.String).check('five')
# Using the Or function
Or(t.Int, t.String).check('1')Trafaret is a validation library that supports converting data structures during the validation process. You can define complex validators using built-in types like t.Int or t.Dict and combine them using the & operator. The & operator allows you to chain a validator with another trafaret or with a function to perform post-validation transformations (e.g., converting a dictionary of integers into a datetime.datetime object).
To validate data, use the .check(data) method. If validation fails, it raises a t.DataError, which can be converted to a dictionary representation using e.as_dict() to identify specific missing or invalid fields.
import datetime
import trafaret as t
# Define a validator that checks for year, month, and day, then converts to datetime
date = t.Dict(year=t.Int, month=t.Int, day=t.Int) & (lambda d: datetime.datetime(**d))
def validate_date(data):
try:
return date.check(data), False
except t.DataError as e:
return False, e.as_dict()
# Example: Missing field
print(validate_date({'year': 2012, 'month': 1}))
# (False, {'day': 'is required'})
# Example: Successful validation and conversion
print(validate_date({'year': 2012, 'month': 1, 'day': 12}))
# (datetime.datetime(2012, 1, 12, 0, 0), False)The preferred method to install trafaret is using pip. This ensures you receive the most recent stable release.
$ pip install trafaretWhen receiving data from web forms, values are often sent as strings (e.g., "True" or "1, 2, 3"). Trafaret can automatically convert these into correct Python types using built-in types like t.StrBool or by passing a custom conversion function into a t.Dict or t.List definition.
For example, you can use a custom function to split a comma-separated string into a list of strings.
import trafaret as t
def comma_to_list(text):
"""Convert string with words separated by comma to list."""
return [
s.strip() for s in text.split(',')
]
create_book_chacker = t.Dict({
'title': t.String,
'authors': comma_to_list,
'sold': t.StrBool,
})
# Example usage:
# create_book_chacker.check({"title": 'Glue', 'authors': 'Welsh,', 'sold': 'True'})
# Returns: {'title': 'Glue', 'authors': ['Welsh', ''], 'sold': True}If you need to install from source, you can clone the repository or download the tarball. Once the source code is available locally, use setup.py to perform the installation.
# Clone the repository
$ git clone git://github.com/Deepwalker/trafaret
# OR download the tarball
$ curl -OL https://github.com/Deepwalker/trafaret/tarball/master
# Install from the source directory
$ python setup.py installYou can use trafaret.constructor.construct to quickly create a validator from a dictionary of types. This is useful for mapping keys to specific data types.
Note: In version 2.0.2+, construct for int and float will automatically use ToInt and ToFloat respectively.
from trafaret.constructor import construct
validator = construct({'a': int, 'b': [str]})
# Valid input
print(validator({'a': 5, 'b': ['lorem', 'ipsum']}))
# {'a': 5, 'b': ['lorem', 'ipsum']}
# Invalid input raises DataError
# validator({'a': 5, 'b': ['gorky', 9]})In web frameworks like aiohttp, you can use a decorator to wrap handlers. This decorator catches t.DataError and automatically returns a JSON response containing the validation errors, preventing the need for repetitive try/except blocks in every handler.
from functools import wraps
import trafaret as t
from aiohttp import web
def with_error(fn):
"""
Decorator for wrapping web handlers to represent
validation errors as JSON responses.
"""
@wraps(fn)
async def inner(*args, **kwargs):
try:
return await fn(*args, **kwargs)
except t.DataError as e:
return web.json_response({
'errors': e.as_dict(value=True)
})
return inner
@with_error
async def create_book(req):
raw_data = await req.json()
# If this fails, the decorator catches t.DataError
data = create_book_chacker.check(raw_data)
return web.json_response({"created": True})Trafaret allows you to chain a validator with a transformation function using the >> operator. This is useful for converting validated raw data (like a dictionary of date components) into a rich object (like a datetime object).
import datetime
import trafaret as t
date = t.Dict(year=t.Int, month=t.Int, day=t.Int) >> (lambda d: datetime.datetime(**d))
assert date.check({'year': 2012, 'month': 1, 'day': 12}) == datetime.datetime(2012, 1, 12)Use t.RegexpRaw to validate a string against a regular expression and then use the >> operator to extract specific groups from the match.
import trafaret as t
c = t.RegexpRaw(r'^name=(\w+)$') >> (lambda m: m.group(1))
assert c.check('name=Jeff') == 'Jeff'You can use t.Key combined with the >> operator within a t.Dict to rename keys as the data is processed.
import trafaret as t
c = t.Dict({(t.Key('uNJ') >> 'user_name'): t.String})
assert c.check({'uNJ': 'Adam'}) == {'user_name': 'Adam'}