Search code examples
pythonjsonobjectserializationstatic

Convert Python Class with Inner Classes and Static Attributes to JSON


I am trying to convert the following to json.

@dataclass
class Attribute:
    name: str
    description: str


class A:
    class B:
        attr1 = Attribute(name="attr1",description="description")
        attr2 = Attribute(name="attr2",description="description")
    class C:
        attr3 = Attribute(name="attr3",description="description")
        attr4 = Attribute(name="attr4",description="description")

The expected output should be

{
    A:{
        B:{
            attr1:{
                name: "attr1",
                description: "description"
            },
            attr2:{
                name: "attr2",
                description: "description"
            }
        },
        C:{
            attr3:{
                name: "attr3",
                description: "description"
            },
            attr4:{
                name: "attr4",
                description: "description"
            }
        }
    }
}

What I have tried without success:

  • using jsonpickle to encode the object (doesn't return the static class variables)

Solution

  • In this case, the simplest option I could suggest would be to define a recursive helper function to iterate over the static fields in a class and call dataclasses.asdict() on each, such as below.

    Note: the following should work in Python 3.8+, as it uses the := walrus operator.

    # noinspection PyProtectedMember, PyUnresolvedReferences
    from dataclasses import asdict, _FIELDS
    
    
    def to_dict(o, include_name=False):
        # check for dataclass instances
        if hasattr(o, _FIELDS):
            return asdict(o)
    
        # check we have a class
        if not isinstance(o, type):
            return None
    
        _dict = {k: res for k, v in o.__dict__.items() if (res := to_dict(v))}
    
        return {o.__qualname__: _dict} if include_name else _dict
    

    Usage would then be as so:

    import json
    from dataclasses import dataclass
    
    
    @dataclass
    class Attribute:
        name: str
        description: str
    
    
    class A:
        class B:
            attr1 = Attribute(name="attr1", description="description")
            attr2 = Attribute(name="attr2", description="description")
    
        class C:
            attr3 = Attribute(name="attr3", description="description")
            attr4 = Attribute(name="attr4", description="description")
    
    
    print(json.dumps(to_dict(A, include_name=True), indent=2))
    

    Prints:

    {
      "A": {
        "B": {
          "attr1": {
            "name": "attr1",
            "description": "description"
          },
          "attr2": {
            "name": "attr2",
            "description": "description"
          }
        },
        "C": {
          "attr3": {
            "name": "attr3",
            "description": "description"
          },
          "attr4": {
            "name": "attr4",
            "description": "description"
          }
        }
      }
    }