如何从 JSL 文档定义的 JSON 模式具体化 attrs 数据类



假设您使用Python JSL库来定义数据的JSON模式,并使用attrs库来快速定义DTO的数据库。

如何根据其 JSON 模式定义(作为类(轻松验证数据结构jsl.Document并将其具体化为符合其 JSL 定义的attrs实例,而无需额外的样板?

因为创建 JSL 文档并复制其定义只是为了获得相应的attrsDTO 感觉不是正确的方法。

定义一个函数以使用 JSL 类型进行实际数据验证,并在字典根据架构进行验证后收集 JSL 文档属性并使用make_class方法动态生成attrs实例。

以下是Python 3.6.1的概念证明:

from typing import TypeVar, Type
import attr
import jsl
import jsonschema

class Demo(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-completion

def reify(schema: Type[T], data: dict) -> T:
"""
Consumes JSON schema (as jsl.Document object) with dictionary data for validation
and if data is valid then “attrs” instance is produced having same structure
as schema object with 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 PyTypeChecker
return 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

作为一个不错的奖励,PyCharm将从JSL文档类中推断出正确的自动完成保留文档。

最新更新