I have the following code for a tree structure:
class Node:
    def __init__(self, node_id: str):
        self.node_id = node_id
        self.children = []
    def add_child(self, node: 'Node'):
        if isinstance(node, Node):
            self.children.append(node)
class ValueNode(Node):
    def __init__(self, value: bool, **kwargs):
        Node.__init__(self, **kwargs)
        self.value = value
class LogicNode(Node):
    def __init__(self, logic_operator: str, **kwargs):
        Node.__init__(self, **kwargs)
        self.logic_operator = logic_operator
a = Node("a")
b = LogicNode("or", node_id="b")
c = ValueNode(True, node_id="c")
d = ValueNode(False, node_id="d")
b.add_child(c)
b.add_child(d)
a.add_child(b)
How can I serialize object a into json and back again into a python object while keeping the correct types and tree structure?
What I tried:
I am trying to serialize this tree structure into json in order to send to an ui through an API. I found about marshmallow but unfortunately, I am unable to figure out how to do it. I have this as schemas atm.
class NodeSchema(Schema):
    node_id = fields.String()
    children = fields.Nested('self', many=True)
    @post_load
    def load(self, data):
        return Node(**data)
class ValueNodeSchema(NodeSchema):
    value = fields.Boolean()
class LogicNodeSchema(NodeSchema):
    logic_operator = fields.String()
Here the problem is that when serialized into json only the attributes of Node are there even if the children are logical node or value node (kinda expected). I found about marshmallow-oneofschema here github but I am unable to use it because with it I have to replace:
# In NodeSchema
children = fields.Nested('self', many=True)
with:
class SomeNodeSchema(OneOfSchema):
    type_schemas = {
        'node': NodeSchema,
        'logic_node': LogicNodeSchema,
        'value_node': ValueNodeSchema,
    }
    def get_obj_type(self, obj):
        if isinstance(obj, LogicNode):
            return 'logic_node'
        if isinstance(obj, ValueNode):
            return 'value_node'
        elif isinstance(obj, Node):
            return 'node'
# In NodeSchema
children = fields.Nested(SomeNodeSchema, many=True)
but this leads to a circular import which makes it impossible.
I found about marshmallow-oneofschema
Although not integrated to the core, I think marshmallow-oneofschema is the recommended way to do polymorphism.
this leads to a circular import
You may pass the name as string to solve the circular import issue.
    children = fields.Nested('SomeNodeSchema', many=True)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With