Open VasLem opened 5 years ago
The issue stems from the use of the double asterisks to pass keyword arguments to the dataclass constructor, e.g. FileParserRequest(**data)
. As mentioned in the original description, the problem does not occur if a JSON string is loaded.
import json
from typing import Set
from dataclasses import dataclass
from dataclasses_json import dataclass_json
@dataclass_json
@dataclass
class Student:
id: int = 0
name: str = ""
@dataclass_json
@dataclass
class Professor:
id: int
name: str
@dataclass_json
@dataclass
class Course:
id: int
name: str
professor: Professor
students: Set[Student]
c_dict = {
"id": 1, "name": "course",
"professor": {"id": 1, "name": "professor"},
"students": [{"id": 1, "name": "student"}]
}
# Using **kwargs to unpack arguments in the constructor
c_unpacked = Course(**c_dict)
# Non-keyword arguments that are already unpacked.
c_construct = Course(1, 'course', Professor(1, 'professor'), {Student(1, 'student')})
# Problem does not occur when loading from JSON
c_json = Course.from_json(json.dumps(c_dict))
assert c_unpacked.to_json() == c_construct.to_json() # Pass
assert isinstance(c_unpacked.professor, Professor) # Fail, type(c1.professor) is dict
assert isinstance(c_construct.professor, Professor) # Pass
assert isinstance(c_json.professor, Professor) # Pass
assert c_json == c_construct # Pass
assert c_unpacked == c_construct # Fail
The unpacking would work if the dictionary contained the dataclass objects. Instead the unpacked dictionary contains another dictionary which overrides the type hint of the dataclass.
c_dict = {
"id": 1, "name": "course",
"professor": Professor(1, 'professor'), # Pass an object, not a dictionary
"students": {Student(1, 'student'), }
}
Using this dictionary in my previous example would work. I would say this is intended behavior.
When I define a dataclass A with a list of nested dataclasses B, by calling the class using a json dictionary, which has also lists inside, the recursive mechanism does not work, leaving the list of dataclasses unrendered, although they are converted to python objects if
from_json
is called.Example
The json:
Result of Converting it with data unrendered:
Result of converting it with from_json():