skip to Main Content

I need to process multiple messages in JSON format. Each message has its own nested structure. I would like to create a Python SDK to process these messages. My idea is to map each JSON structure into a set of nested Python classes. Currently, I’m doing it manually. But it is a tedious task.

Please find an example JSON message below:

{
    "GlobalGnbId": {
        "PlmnIdentity": {
            "Data": [
                 19,
                241,
                132
            ]
        },
        "GnbId": {
            "Value":   1,
            "Length": 22
        }
    },
    "OptionalGnbDuId": 1
}

Please find below my own handcrafted set of Python classes to work with this JSON message:

class PlmnIdentity(BaseModel):
    """Class for PLMN identity"""
    Data: list[int]

class GnbId(BaseModel):
    """Class for gNodeB ID"""
    Value:  int
    Length: int

class GlobalGnbId(BaseModel):
    """Class for global gNodeB ID"""
    PlmnIdentity:    PlmnIdentity
    GnbId:           GnbId

class NodeId(BaseModel):
    """Class for node ID"""
    GlobalGnbId:     GlobalGnbId
    OptionalGnbDuId: int

Finally, please find below a full minimal example:

from pydantic import BaseModel, TypeAdapter

import json

class PlmnIdentity(BaseModel):
    """Class for PLMN identity"""
    Data: list[int]

class GnbId(BaseModel):
    """Class for gNodeB ID"""
    Value:  int
    Length: int

class GlobalGnbId(BaseModel):
    """Class for global gNodeB ID"""
    PlmnIdentity:    PlmnIdentity
    GnbId:           GnbId

class NodeId(BaseModel):
    """Class for node ID"""
    GlobalGnbId:     GlobalGnbId
    OptionalGnbDuId: int

node_id_str = 
"""
{
    "GlobalGnbId": {
        "PlmnIdentity": {
            "Data": [
                 19,
                241,
                132
            ]
        },
        "GnbId": {
            "Value":   1,
            "Length": 22
        }
    },
    "OptionalGnbDuId": 1
}
"""

# NodeId as class
node_id_class = TypeAdapter(NodeId).validate_json(node_id_str)

print(node_id_class)

print(node_id_class.GlobalGnbId)
print(node_id_class.GlobalGnbId.PlmnIdentity)
print(node_id_class.GlobalGnbId.PlmnIdentity.Data)

print(node_id_class.GlobalGnbId.GnbId)
print(node_id_class.GlobalGnbId.GnbId.Value)
print(node_id_class.GlobalGnbId.GnbId.Length)

print(node_id_class.OptionalGnbDuId)

# NodeId as dictionary
node_id_dict = node_id_class.model_dump()

print(node_id_dict)

My question is there an automatic or semi-automatic way to map a nested JSON message to a set of Python classes?

2

Answers


  1. You can use Python’s dataclasses module alongside libraries like pydantic or dataclasses-json to map JSON to nested Python classes automatically.

    Login or Signup to reply.
  2. I strongly recommend exploring dataclass-wizard! This fast, strongly-typed de/serialization library is built on dataclasses and features minimal dependencies. It’s well-tested and ready for production use.

    Disclaimer: I am the author/maintainer of this library.

    Generating Dataclass Schema

    First, install the package:

    pip install dataclass-wizard
    

    Next, use the included wiz CLI utility to generate a schema for your JSON data:

    echo '{
        "GlobalGnbId": {
            "PlmnIdentity": {
                "Data": [
                     19,
                    241,
                    132
                ]
            },
            "GnbId": {
                "Value":   1,
                "Length": 22
            }
        },
        "OptionalGnbDuId": 1
    }' | wiz gs -x
    

    That gave me Python dataclass schema to use:

    from __future__ import annotations
    
    from dataclasses import dataclass
    
    from dataclass_wizard import JSONWizard
    
    
    @dataclass
    class Data(JSONWizard):
        """
        Data dataclass
    
        """
        global_gnb_id: GlobalGnbId
        optional_gnb_du_id: int
    
    
    @dataclass
    class GlobalGnbId:
        """
        GlobalGnbId dataclass
    
        """
        plmn_identity: PlmnIdentity
        gnb_id: GnbId
    
    
    @dataclass
    class PlmnIdentity:
        """
        PlmnIdentity dataclass
    
        """
        data: list[int]
    
    
    @dataclass
    class GnbId:
        """
        GnbId dataclass
    
        """
        value: int
        length: int
    

    Now I can proceed to de/serialize the data using the Dataclass Wizard library:

    from __future__ import annotations
    
    from dataclasses import dataclass
    
    from dataclass_wizard import JSONWizard
    
    
    @dataclass
    class Data(JSONWizard):
        """
        Data dataclass
    
        """
        global_gnb_id: GlobalGnbId
        optional_gnb_du_id: int
    
    
    @dataclass
    class GlobalGnbId:
        """
        GlobalGnbId dataclass
    
        """
        plmn_identity: PlmnIdentity
        gnb_id: GnbId
    
    
    @dataclass
    class PlmnIdentity:
        """
        PlmnIdentity dataclass
    
        """
        data: list[int]
    
    
    @dataclass
    class GnbId:
        """
        GnbId dataclass
    
        """
        value: int
        length: int
    
    d = Data.from_json("""
    {
        "GlobalGnbId": {
            "PlmnIdentity": {
                "Data": [
                     19,
                    241,
                    132
                ]
            },
            "GnbId": {
                "Value":   1,
                "Length": 22
            }
        },
        "OptionalGnbDuId": 1
    }
    """)
    
    print(repr(d))
    

    Result:

    Data(global_gnb_id=GlobalGnbId(plmn_identity=PlmnIdentity(data=[19, 241, 132]), gnb_id=GnbId(value=1, length=22)), optional_gnb_du_id=1)
    

    As you can see, one of the main benefits is the automatic letter-case transformation. For example, TitleCase in your JSON input is seamlessly mapped to a snake_case field name, following Python’s convention.

    Hope this helps!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search