s-knibbs / dataclasses-jsonschema

JSON schema generation from dataclasses
MIT License
166 stars 38 forks source link

Nested unions are not (de-)serialized correctly #133

Open jonasehrlich opened 4 years ago

jonasehrlich commented 4 years ago

When using nested Unions, deserialization does not happen correctly. Consider the following structure:

class StatusEnum(Enum):
    IDLE = auto() 
    RUNNING = auto()

@dataclass
class Cfg(JsonSchemaMixin):
    status: ty.Dict[str, ty.Union[ty.List[StatusEnum], ty.List[str], str]] = field(default_factory=lambda: {
        'name': 'orchestrator',
        'worker_state': [StatusEnum.IDLE, StatusEnum.IDLE],
        'worker_names': ['worker1', 'worker2']
    })

# Just for reference using a different type hint order
@dataclass
class Cfg2(JsonSchemaMixin):
    status: ty.Dict[str, ty.Union[str, ty.List[StatusEnum], ty.List[str]]] = field(default_factory=lambda: {
        'name': 'orchestrator',
        'worker_state': [StatusEnum.IDLE, StatusEnum.IDLE],
        'worker_names': ['worker1', 'worker2']
    })

Serialization

print(Cfg().to_dict())
{'status': {'name': 'orchestrator', 'worker_state': [<StatusEnum.IDLE: 1>, <StatusEnum.IDLE: 1>], 'worker_names': ['worker1', 'worker2']}}

print(Cfg2().to_dict())
{'status': {'name': 'orchestrator', 'worker_state': [<StatusEnum.IDLE: 1>, <StatusEnum.IDLE: 1>], 'worker_names': ['worker1', 'worker2']}}

# expected output
{'status': {'name': 'orchestrator', 'worker_state': [1, 1], 'worker_names': ['worker1', 'worker2']}}

Deserialization


d = {"status": {"name": ['orchestrator'], "worker_state": [1, 1], "worker_names": ["worker1", "worker2"]}}
print(Cfg.from_dict(d))
Cfg(status={'name': ['orchestrator'], 'worker_state': [1, 1], 'worker_names': ['worker1', 'worker2']})

print(Cfg.from_dict(d))
Cfg(status={'name': ['orchestrator'], 'worker_state': [1, 1], 'worker_names': ['worker1', 'worker2']})

# expected output
Cfg(status={'name': ['orchestrator'], 'worker_state': [<StatusEnum.IDLE: 1>, <StatusEnum.IDLE: 1>], 'worker_names': ['worker1', 'worker2']})

I assume the better solutions for nested structures would be, to use another dataclass, but this is not possible, because we are on the transition to use dataclasses-jsonschema. Is there another way this kind of nested union could be achieved?