Python 数据类用棉花糖进行循环解析

Python dataclasses circular parsing with marshmallow

我正在使用 JSON 数据结构,并试图将其表示为数据类。数据结构(部分)是循环的,我希望嵌套数据结构也能整齐地表示为数据类。

我在正确解析数据类时遇到了一些问题。请参阅下面的简化示例:

from typing import List, Optional, Union


class SchemaTypeName(Enum):
    LONG = "long"
    NULL = "null",
    RECORD = "record"
    STRING = "string"


@dataclass_json
@dataclass
class SchemaType():

    type: Union[
        SchemaTypeName,
        'SchemaType',
        List[
            Union[
                SchemaTypeName,
                'SchemaType'
            ]
        ]
    ]

    fields: Optional[List['SchemaType']] = None
    name: Optional[str] = None

下面是使用一些示例数据调用 from_dict 后返回的对象的打印输出。请注意,嵌套对象(用箭头指示)未正确解析为数据类。

SchemaType(
    type=[
        'null', 
------> {
            'fields': [
                {'name': 'id', 'type': 'string'}, 
                {'name': 'date', 'type': ['null', 'long']}, 
                {'name': 'name', 'type': ['null', 'string']}
            ],
            'type': 'record'
        }
    ]
)

我是否错误地声明了 type 字段的类型提示?

我将 Python 3.9dataclasses_json==0.5.2marshmallow==3.11.1 一起使用。

我发现问题与 dataclasses_json 在列表中时未正确解码我的元素有关。在列表中混合类型会导致解码器 return 基本 stringdict 的列表,而不会将它们转换为 SchemaTypeSchemaTypeName 的实例.

但是,dataclasses_json 允许您为任何特定字段配置自定义解码器函数。这是通过从 dataclasses_json 导入 config 函数并将其作为 fieldmetadata 关键字参数提供来完成的。接下来,将解码器函数包含为 config.

decoder 关键字参数

请参阅下面的更新示例。使用 schemaTypeDecoder 函数,我能够将我的数据转换为正确的类型。

from dataclasses import field
from dataclasses_json import config

class SchemaTypeName(Enum):
    ARRAY = "array"
    LONG = "long"
    NULL = "null"
    OBJECT = "object"
    RECORD = "record"
    STRING = "string"


def schemaTypeDecoder(data: Union[str, dict, List[Union[str, dict]]]):

    def transform(schemaType: Union[str, dict]):
        if isinstance(schemaType, str):
            return SchemaTypeName(schemaType)
        else:
            return SchemaType.from_dict(schemaType)

    if isinstance(data, list):
        return [transform(schemaType) for schemaType in data]
    else:
        return transform(data)


@dataclass_json()
@dataclass
class SchemaType():
    type: Union[
        SchemaTypeName,
        'SchemaType',
        List[
            Union[
                SchemaTypeName,
                'SchemaType'
            ]
        ]
    ] = field(
        metadata=config(
            decoder=schemaTypeDecoder
        )
    )

    fields: Optional[List['SchemaType']] = None
    name: Optional[str] = None