How to deserialise enumeration with string representation?

4.7k views Asked by At

I would like to create a class, which has an enumeration as an attribute. This enumeration should have a string representation that shows up as human-readable value when dumping the instance of the class that uses the enum attribute as a JSON string. In the minimal working example below, I created three enumerations in three different ways.

After the deserialization, each attribute shows us that it comes from an enumeration except the enumeration with a string representation. It is just a string.

If it is not possible to realize such a structure, I would like to know why.

Requirements

If you would like to test it, you have to install jsons and attrs with

pip install attrs jsons

Minimal working example

Here you see a minimal working example.

import jsons
import attr

from enum import Enum

# ----------------------------------------------------
# create enumeration with the help of a dictionary

fruits = {
    "PINEAPPLE": "PINEAPPLE",
    "APPLE": "APPLE",
    "ORANGE": "ORANGE",
    "BANANA": "BANANA",
}

Fruit = Enum("FRUITS", fruits)

# ----------------------------------------------------
# create a classical enumeration


class Nut(Enum):

    PEANUT = 1
    HAZELNUT = 2
    CASHEW = 3
    WALNUT = 4


# ----------------------------------------------------
# create enumeration with a string representation


class Vegetable(str, Enum):

    BROCCOLI = "BROCCOLI"
    CUCUMBER = "CUCUMBER"
    POTATO = "POTATO"
    ONION = "ONION"


# ----------------------------------------------------
# create a class which uses the enumerations


@attr.s(auto_attribs=True, kw_only=True)
class Order(jsons.JsonSerializable):
    fruit: Fruit
    nut: Nut
    vegetable: Vegetable


# ----------------------------------------------------
# initialize an order object, serialize and deserialize it

order = Order(fruit=Fruit.APPLE, nut=Nut.PEANUT, vegetable=Vegetable.CUCUMBER)

json_string: str = Order.dumps(order)

order_deserialised: Order = Order.loads(json_string)

Structure of the order and order_deserialised variable:

order:              Order(fruit=<FRUITS.APPLE: 'APPLE'>, nut=<Nut.PEANUT: 1>, vegetable=<Vegetable.CUCUMBER: 'CUCUMBER'>)

order_deserialised: Order(fruit=<FRUITS.APPLE: 'APPLE'>, nut=<Nut.PEANUT: 1>, vegetable='CUCUMBER')

As you can see, the order_deserialised shows the vegetable as a string and not an enumeration.

1

There are 1 answers

0
relent95 On

Maybe you already know this, but I am answering for future readers.

This problem was fixed in JSONS 1.6.1, as you can see in the following example.

import enum
import jsons

class Vegetable(str, enum.Enum):
    BROCCOLI = "BROCCOLI"

print(jsons.loads(jsons.dumps(Vegetable.BROCCOLI), Vegetable))
# This will output "Vegetable.BROCCOLI" with JSONS 1.6.1 or later

And deriving a class like class Vegetable(str, Enum) is perfectly fine, unlike what others commented on the question. A similar idea was added as the StrEnum in Python 3.11.