Sam7919
Sam7919

Reputation: 631

How should I JSON-serialize Enum-children?

If I write

import json

class Color():
    FUSCHIA = 0x00
    TURQUOISE = 0x01
    EMERALD = 0x02


def my_default_serializer(o):
    return o.__dict__


def get_colors():
    return json.dumps(
        {
            'dark_bg': True,
            'colors_batch': [Color.TURQUOISE,
                             Color.EMERALD]
        },
        default=my_default_serializer
    )

print(get_colors())

then I get, as expected:

{"dark_bg": true, "colors_batch": [1, 2]}

Now suppose I modernize this code by introducing enum.Enum. Among other things, this is handy because Enum will parse a string (read from a file, for example), and hence I replace the code above with:

import json
from enum import Enum

class Color(Enum):
    FUSCHIA = 0x00
    TURQUOISE = 0x01
    EMERALD = 0x02


def my_default_serializer(o):
    return o.__dict__


def get_colors():
    return json.dumps(
        {
            'dark_bg': True,
            'colors_batch': [Color['TURQUOISE'],
                             Color['EMERALD']]
        },
        default=my_default_serializer
    )

print(get_colors())

This introduces the error:

AttributeError: 'mappingproxy' object has no attribute '__dict__'

(and if I don't specify the default serializer, I get TypeError: Object of type 'Color' is not JSON serializable ).

How should I JSON-serialize Enum-children?

Upvotes: 2

Views: 721

Answers (1)

balderman
balderman

Reputation: 23815

see below - seems to work. The idea is to override default method of JSONEncoder, check if the incoming argument is an instance of a Color and handle it.

import json
from enum import Enum


class Color(Enum):
    FUSCHIA = 0x00
    TURQUOISE = 0x01
    EMERALD = 0x02


class EnumEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Enum):
            return {"__enum__": str(obj)}
        return json.JSONEncoder.default(self, obj)


def get_colors():
    return json.dumps(
        {
            'dark_bg': True,
            'colors_batch': [Color['TURQUOISE'],
                             Color['EMERALD']]
        }, cls=EnumEncoder
    )


print(get_colors())

Upvotes: 3

Related Questions