Skip to main content

Liaison is a Python library for defining schemas, parsing and validating payloads

Project description

Liaison

A zero dependency Python library for defining schemas, parsing and validating payloads.

CI

Liaison doesn't aim to be too clever. It doesn't use descriptors, fancy metaprogramming or type hints for defining your schema. Simply inherit from the Schema base class, define your fields and call parse. In return, you'll receive a simple Namespace object containing your parsed data.

Goals:

  • Simplicity
  • Extensibility
  • Speed
  • 100% test coverage

Installation:

pip install liaison

Example:

from liaison import Schema, ValidationError
from liaison.fields import StringField, IntField, BoolField, ListField, DateTimeField


class UserSchema(Schema):

    name = StringField(required=True)
    email = StringField(required=True)
    age = IntField(min_val=18)
    date_of_birth = DateTimeField(date_format="%d-%m-%Y")
    subscribed = BoolField(default=False)
    tags = ListField(min_len=1)


data = {
    "name": "Bar",
    "email": "foo@bar.com",
    "age": 21,
    "tags": ["Python"]
}

result = UserSchema.parse(data)

print(result.name, result.email, result.age, result.tags)  # Bar foo@bar.com 21 ['Python']

Handling validation errors:

data = {
    "name": "Bar",
    "email": "foo@bar.com",
    "age": 16
}

try:
    result = UserSchema.parse(data)
except ValidationError as e:
    print(e)  # Value for 'age' must be at least 18

Defining custom field validators via the <field>.validator decorator:

class UserSchema(Schema):

    name = StringField(required=True)
    email = StringField(required=True)
    age = IntField(min_val=18)

    @name.validator
    def validate_name(self, key, value):
        # Define a custom validator, overrides the default validation method
        if value == "Foo":
            raise ValidationError(f"'{value}' is not a valid value for '{key}'")
        return value

Custom validators can also be passed as a parameter to the field:

def name_validator(schema_cls, key, value):
    if value in ("Foo", "Bar", "Baz"):
        raise ValidationError(f"'{value}' is not a valid value for '{key}'")
    return value


class UserSchema(Schema):

    name = StringField(required=True, validator=name_validator)
    email = StringField(required=True)
    age = IntField(min_val=18)

Fields

Use fields to define your schema. By default, all fields accept the following common parameters:

Parameter Type Description Default
required bool If the value is required False
default Any A default value None
choices List[Any] A list of choices None
validator Callable A function to override the default validation method None
strict_type bool If True, only accept the fields data type False

StringField - Defining strings

Parameter Type Description Default
min_len int The minimum length None
max_len int The maximum length None

IntField - Defining integers

Parameter Type Description Default
min_val int The minimum value None
max_val int The maximum value None

FloatField - Defining floats

Parameter Type Description Default
min_val int The minimum value None
max_val int The maximum value None

BoolField - Defining booleans

ListField - Defining lists

Parameter Type Description Default
min_len int The minimum length None
max_len int The maximum length None

SetField - Defining sets

Note - SetField shares the same behaviour as ListField, returning a set.

Parameter Type Description Default
min_len int The minimum length None
max_len int The maximum length None

DictField - Defining dictionaries

Parameter Type Description Default
min_len int The minimum length None
max_len int The maximum length None

DateTimeField - Defining datetimes

Note - DateTimeField fields will return datetime objects

Parameter Type Description
date_format str The date format

UUIDField - Defining UUIDs

Note - UUIDField fields will NOT return a UUID obejct, it will return a string.

Namespace

Calling the parse method on a Schema object will return a Namespace object, holding the parsed values as attributes.

from liaison import Schema
from liaison.fields import StringField, IntField, BoolField, FloatField, UUIDField


class RESTBaseSchema(Schema):

    offset = IntField(min_val=0, default=0)
    limit = IntField(max_val=100)
    search = StringField()


class ProductsRESTSchema(RESTBaseSchema):

    product_id = UUIDField()
    category = StringField()
    price = FloatField()
    in_stock = BoolField()


payload = {
    "offset": 10,
    "category": "shoes",
    "in_stock": True
}

result = ProductsRESTSchema.parse(payload)  

print(result.offset, result.limit, result.search, result.category, result.in_stock)
# 10 None None shoes True

Namespace objects have a to_dict method, returning a dictionary of the Namespace attributes and values:

print(result.to_dict())
# {'category': 'shoes', 'in_stock': True, 'limit': None, 'offset': 10, 'price': None, 'product_id': None, 'search': None}

An optional exclude parameter can be included to exclude certain attributes:

print(result.to_dict(exclude=("offset", "limit", "search")))
# {'category': 'shoes', 'in_stock': True, 'price': None, 'product_id': None}

Defining custom fields

Create your own fields and validation logic by inheriting from any of the field classes and implementing a validate method.

Note - The validate method must accept 2 params (key, value)

from liaison import Schema, ValidationError
from liaison.fields import StringField


class PasswordField(StringField):

    def validate(self, key, value):
        value = super().validate(key, value)
        if len(value) < 9:
            raise ValidationError("Value for 'password' must be at least 9 characters in length")
        # etc...
        return value


class UserSchema(Schema):

    username = StringField(required=True)
    password = PasswordField()


payload = {
    "username": "FooBar",
    "password": "password"
}

try:
    result = UserSchema.parse(payload)
except ValidationError as e:
    print(e)  # Value for 'password' must be at least 9 characters in length
    
payload = {
    "username": "FooBar",
    "password": "password12345!"
}

result = UserSchema.parse(payload)
print(result.password)  # password12345!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

liaison-0.3.tar.gz (5.7 kB view details)

Uploaded Source

Built Distribution

liaison-0.3-py3-none-any.whl (6.1 kB view details)

Uploaded Python 3

File details

Details for the file liaison-0.3.tar.gz.

File metadata

  • Download URL: liaison-0.3.tar.gz
  • Upload date:
  • Size: 5.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.5

File hashes

Hashes for liaison-0.3.tar.gz
Algorithm Hash digest
SHA256 ad8092967d7b38ef1157ee390bb73c3e27ca2b64e609383a66c3418f25e9e143
MD5 3c47a01fe4c1eaf2229fc2ecad018f85
BLAKE2b-256 b7ff3849cd1aab615d9d472f704c3a68378431c6604f3e730b16151dd2283f16

See more details on using hashes here.

File details

Details for the file liaison-0.3-py3-none-any.whl.

File metadata

  • Download URL: liaison-0.3-py3-none-any.whl
  • Upload date:
  • Size: 6.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.9.5

File hashes

Hashes for liaison-0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 35ab3d77ed116bdf72e18cfc56ab64fcda7ceff642c0ab226384a9b63222862a
MD5 9cfe5561729789d09ccefdd1cf44105a
BLAKE2b-256 59ded0b6c4e9152b147cbbb3e9aa5bd74602a737aabfa17b826919c273c17cd8

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page