Deserialize JSON string to a class instance automatically in Python

Question:

Assume I have several classes:

class Assignee:
    gid: str
    name: str
    
class Task:
    gid: str
    name: str
    created_at: datetime
    assignee: Assignee

and I receive a JSON, that I want to translate into my Task class instance:

{
 "gid": "#1",
 "name": "my task",
 "created_at": "2022-11-02T10:25:49.806Z",
 "assignee": {
  "gid": "#a1",
  "name": "assignee name"
 }
}

I need to get the strong typed result, not a dict. Is it possible to convert from JSON string to a class instance automatically?
In C# we can do it with JsonConvert.DeserializeObject<Task>(json_string).
In Python I found a jsonpickle library, but as far as I see, it cannot do it automatically. Am I missing anything?

In real life I have many more classes and JSON properties.

Asked By: Alex Sham

||

Answers:

Not quite what you are asking, but the json module already produces suitable dicts. All you need to do is define how to instantiate your classes given a dict.

Part of this requires you to assume what type each key’s value must be instantiated as.

class Assignee:
    @classmethod
    def from_dict(cls, d):
        return cls(d['gid'], d['name'])

class Task:
    @classmethod
    def from_dict(cls, d):
        return cls(d['gid'], d['name'], d['created_at'], Assignee.from_dict(d['assignee']))

t = Task.from_dict(json.load('{"gid": "#1", ...}'))
Answered By: chepner

Assuming the json properties match the property names exactly in the classes, you can use kwargs in the constructors to put the object together.

import json

class Assignee:
    def __init__(self, gid, name):
        self.gid = gid
        self.name = name

class Task:
    def __init__(self, gid, name, created_at, assignee):
        self.gid = gid
        self.name = name
        self.created_at = created_at
        self.assignee = Assignee(**assignee)

json_string = '{ "gid": "123", "name": "Bob", "created_at": "1/1/1990", "assignee": { "gid": "234", "name": "Alice" } }'

# Instantiate Task with kwargs loaded from json
my_task = Task(**json.loads(json_string))

print(my_task.assignee.name)
# prints 'Alice'
Answered By: DJSDev

Use pydantic. It has type validation (and other cool features) and is very easy to use:

from pydantic import BaseModel
from datetime import datetime

class Assignee(BaseModel):
    gid: str
    name: str
    

class Task(BaseModel):
    gid: str
    name: str
    created_at: datetime
    assignee: Assignee


data = {
    "gid": "#1",
    "name": "my task",
    "created_at": "2022-11-02T10:25:49.806Z",
    "assignee": {
        "gid": "#a1",
        "name": "assignee name"
    }
}

Task(**data)
>>>Task(gid='#1', name='my task', created_at=datetime.datetime(2022, 11, 2, 10, 25, 49, 806000, tzinfo=datetime.timezone.utc), assignee=Assignee(gid='#a1', name='assignee name'))
Answered By: Plagon
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.