7

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.

7
  • Why are you inheriting from str??? class Vegetable(str, Enum):? This is likely throwing off the attrs/jsons libraries, somewhere I suspect, there is some check isinstance(x, str), and it isn't handling str subtypes.... "create enumeration with a string representation" That isn't a reasonable way of doing this. Just write a __str__ and a __repr__ method. Inheriting from str seems to be your issue. Your enumeration is a string, that is what inheriting from str does, so it's not surprising that it is being treated as one. Commented Dec 17, 2020 at 11:28
  • Fundamentally, it isn't clear what you mean by "create an enumeration with a string reprsentation", what is it you are tryin to achieve by inheriting from str? Commented Dec 17, 2020 at 11:36
  • Yeah you are both right. I saw this structure on another stack overflow entry I stick to the dictionary ansatz. Thanks for your help =) Commented Dec 18, 2020 at 21:18
  • Or of course, you can just not inherit from str, so class Vegetable(Enum): ... Commented Dec 18, 2020 at 21:21
  • 2
    What do you mean, "the value, not only the number", what number? In any case, your library almost certainly allows you to control the serialization any way you want. Having an enum type inherit from str defeats the whole purpose of enum in the same way as having it inherit from int. I re-opened the question, because I don't think the duplicate was a great fit. Commented Dec 19, 2020 at 20:59

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.