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"