'Create a class from a nested JSON
I am struggling with this problem, I have to make a class out of a json-rpc client I get responses like this
{"jsonrpc":"2.0","id":1,"result":{"os":"linux","platform":"ubuntu","platformFamily":"debian","platformVersion":"20.04","kernelVersion":"5.4.0-107-generic","memoryTotal":4021989376,"memoryFree":725327872,"numCPU":2,"numGoroutine":169645}}
I'd like to extrapolate all the keywords/values under result but i don't have any idea how to do...
I tried with this:
class foo:
def __init__(self, jsonrpc, id, result):
self.jsonrpc = jsonrpc
self.id = id
self.result = result
@classmethod
def from_json(cls, json_str):
json_dict = json.loads(json_str)
return cls(**json_dict)
But I have the class on the upper level, and is not useful for me. I tried also to add the other keywords in the constructor but seems cannot reach the level under so compiler say arguments are missing
.
Solution 1:[1]
I would personally suggest using the dataclass-wizard
for this task. This is a third-party JSON de/serialization library built on top of the Python dataclasses module.
Additionally, the library exposes a command-line utility named wiz
, which can be used to generate a dataclass schema for arbitrary JSON input, which would certainly be useful in this case.
For example - on Mac/Linux:
$ echo '{"jsonrpc":"2.0","id":1,"result":{"os":"linux","platform":"ubuntu","platformFamily":"debian","platformVersion":"20.04","kernelVersion":"5.4.0-107-generic","memoryTotal":4021989376,"memoryFree":725327872,"numCPU":2,"numGoroutine":169645}}' \
| wiz gs -x
Results in the following dataclass schema:
from __future__ import annotations
from dataclasses import dataclass
from dataclass_wizard import JSONWizard
@dataclass
class Data(JSONWizard):
"""
Data dataclass
"""
jsonrpc: float | str
id: int
result: Result
@dataclass
class Result:
"""
Result dataclass
"""
os: str
platform: str
platform_family: str
platform_version: float | str
kernel_version: str
memory_total: int
memory_free: int
num_cpu: int
num_goroutine: int
And you can then load the JSON string in the original question above as a dataclass instance, using the from_json
method:
string = '{"jsonrpc":"2.0", ...}'
instance = Data.from_json(string)
print(repr(instance))
NB: One minor point that you might notice, is that for some of the JSON values like "jsonrpc": "2.0"
, the generated dataclass schema shows as Union[float, str]
.
You can then force-resolve these encoded numeric strings to their corresponding numeric Python types, by passing the -f / --force-strings
option to the wiz
tool. The generated dataclass field should then show asjsonrpc: float
for example.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |