如何从 JSL 文档定义的 JSON 模式中具体化属性数据 class
How to materialize attrs data class from JSON schema defined by JSL document
假设您使用 Python JSL library for defining JSON schema of your data and you using attrs library for quick definition of your DTO.
您如何根据其 JSON 架构定义(如 jsl.Document
class)轻松验证数据结构并将其具体化为 attrs 实例符合其 JSL 定义而无需额外的样板文件?
因为创建 JSL 文档并复制它们的定义只是为了拥有相应的 attrs DTO 感觉不是正确的方法。
定义一个函数来使用 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 文档 class.
中推断出正确的自动完成保留文档
假设您使用 Python JSL library for defining JSON schema of your data and you using attrs library for quick definition of your DTO.
您如何根据其 JSON 架构定义(如 jsl.Document
class)轻松验证数据结构并将其具体化为 attrs 实例符合其 JSL 定义而无需额外的样板文件?
因为创建 JSL 文档并复制它们的定义只是为了拥有相应的 attrs DTO 感觉不是正确的方法。
定义一个函数来使用 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 文档 class.
中推断出正确的自动完成保留文档