本文介绍了如何从JSL文档定义的JSON模式实现attrs数据类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您使用Python JSL 库来定义 JSON模式,并且您使用 attrs 库,用于快速定义 DTO .

Assuming you using Python JSL library for defining JSON schema of your data and you using attrs library for quick definition of your DTO.

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

How can you easily validate data structure against its JSON schema definition (as jsl.Document class) and reify it into attrs instance conforming to its JSL definition without extra boilerplate?

由于创建JSL文档并重复其定义只是为了具有相应的 attrs DTO,所以感觉不是正确的方法.

Because creating JSL documents and duplicate their definitions just to have a corresponding attrs DTO doesn’t feel to be the right way.

推荐答案

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

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.

这是Python 3.6.1的概念证明:

Here is proof of concept for 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文档类中推断出正确的自动完成保存文档,这是一个不错的奖励.

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

这篇关于如何从JSL文档定义的JSON模式实现attrs数据类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-16 00:36