Skip to content Skip to sidebar Skip to footer

How To Materialize Attrs Data Class From Json Schema Defined By Jsl Document

Assuming you using Python JSL library for defining JSON schema of your data and you using attrs library for quick definition of your DTO. How can you easily validate data structure

Solution 1:

Define a function to consume JSL type for validation with actual data and once dictionary validates against schema collect JSL document attributes and use make_class method to produce attrs instance dynamically.

Here is proof of concept for Python 3.6.1:

from typing import TypeVar, Type

import attr
import jsl
import jsonschema


classDemo(jsl.Document):
    """
    Demo schema
    """
    ip = jsl.IPv4Field(required=True)
    """IPv4 address string"""
    headers = jsl.DictField(required=True,
                            min_properties=1,
                            additional_properties=jsl.StringField())
    """Dictionary of HTTP headers"""
    email = jsl.EmailField()
    """Optional User email"""


T = TypeVar('T')  # Nice hack using generic type hinting. It preserves auto-completiondef reify(schema: Type[T], data: dict) -> T:
    """
    Consumes JSON schema (as jsl.Document object) with dictionary data for validation
    andif data is valid then “attrs” instance is produced having same structure
    as schema objectwith populated data.

    :param T schema: Schema type (as jsl.Document type.)
    :param dict data: Data dictionary for validation against **schema**.
    :return: Schema transformed into equivalent **attrs** instance with populated
    **data**.
    :rtype: T
    :raises: ValueError — When **data** does not conforms with **schema**.
    """
    try:
        jsonschema.validate(data, schema.get_schema())
        props = [name for name, _ in schema.get_schema()['properties'].items()]
        fields = {key: attr.ib(default=None) for key in props}
        # noinspection PyTypeCheckerreturn attr.make_class(schema.__name__, fields)(**data)
    except jsonschema.ValidationError as e:
        raise ValueError(f'Payload does not conform to JSON schema: {e.message}')


demo = reify(Demo, {'ip': '1.2.3.4', 'headers': {'Accept': '*/*'}})

print(demo)
print(f"{demo.ip} Headers: {demo.headers} Email {demo.email}")

# Prints:# Demo(ip='1.2.3.4', headers={'Accept': '*/*'}, email=None)# 1.2.3.4 Headers: {'Accept': '*/*'} Email None

As a nice bonus, PyCharm will infer correct auto-completion preserving documentation from JSL document class.

Post a Comment for "How To Materialize Attrs Data Class From Json Schema Defined By Jsl Document"