How to serialize objects which members are not serializable directly, but their str() representation is?

Viewed 84

I receive dicts such as (without knowing the exact structure in advance)

{
  'a': 1,
  'id': UUID('6b3acb30-08bf-400c-bc64-bf70489e388c'),
}

This dict is not directly serializable, but when casting the value of id to an str - it is:

import json
import uuid

print(json.dumps({
  'a': 1,
  'id': str(uuid.UUID('6b3acb30-08bf-400c-bc64-bf70489e388c')),
}))

# outputs {"a": 1, "id": "6b3acb30-08bf-400c-bc64-bf70489e388c"}

In the general case where I have elements which need to be casted to an str before being serializable, is there a generic (pythonic) way to make the transformation automatically?

2 Answers

The best option is to override JSONEncoder.default method:

class MyJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, uuid.UUID):
            return str(o)
        return super().default(o)

print( MyJSONEncoder().encode(data) )

If you want to stringify everything that the default encoder cannot handle, you may use the following trick, although I would recommend to take control over the types you want to support.

class MyJSONEncoder(json.JSONEncoder):
    def default(self, o):
        try:
            return super().default(o)
        except TypeError:
            return str(o)

print( json.dumps(data, cls=MyJSONEncoder) )

DOCS: https://docs.python.org/3/library/json.html#json.JSONEncoder.default

No there is not, but you can check for the data items individually and convert when needed. This way you do not need to know the data structure in advance. Consider the following:

import json
import uuid

data = {
  'a': 1,
  'id': UUID('6b3acb30-08bf-400c-bc64-bf70489e388c')
}

for k, v in data.items():
    try:
        json.dumps(v)
    except TypeError:
        data[k] = str(uuid.v)

print(json.dumps(data))

# outputs {"a": 1, "id": "6b3acb30-08bf-400c-bc64-bf70489e388c"}
Related