madman-bob / python-dataclasses-serialization

Serialize/deserialize Python dataclasses to various other data formats
MIT License
25 stars 11 forks source link

Add deserializer for Enum #7

Open kitschen opened 4 years ago

kitschen commented 4 years ago

You can add a generic serializer which works for all Enums like so

@JSONSerializer.register_serializer(Enum)
def Enum_serializer(obj: Enum) -> str:
    return obj.name

@JSONSerializer.register_deserializer(Enum)
def Enum_deserializer(cls, name: str) -> Enum:
    try:
        return cls[name]
    except KeyError:
        raise DeserializationError()

Maybe add this to default JSONSerializer or point to it in the docs?

Example test:

from dataclasses import dataclass
from enum import Enum, auto
from typing import Optional
from unittest import TestCase

from dataclasses_serialization.json import JSONSerializer
from dataclasses_serialization.serializer_base import DeserializationError

class Gender(Enum):
    male = auto()
    female = auto()

@dataclass(frozen=True)
class Employee:
    name: Optional[str]
    gender: Optional[Gender]

@JSONSerializer.register_serializer(Enum)
def Enum_serializer(obj: Enum) -> str:
    return obj.name

@JSONSerializer.register_deserializer(Enum)
def Enum_deserializer(cls, name: str) -> Enum:
    try:
        return cls[name]
    except KeyError:
        raise DeserializationError()

class TestEmployee(TestCase):
    def testSerializingNone(self):
        emp = Employee(None, None)
        resDict = JSONSerializer.serialize(emp)

        emp2 = JSONSerializer.deserialize(Employee, resDict)
        self.assertEqual(emp, emp2)

    def testSerializingValue(self):
        emp = Employee("Sarah", Gender.female)
        resDict = JSONSerializer.serialize(emp)

        emp2 = JSONSerializer.deserialize(Employee, resDict)
        self.assertEqual(emp, emp2)
madman-bob commented 4 years ago

I'd happily include this as an enum_name_serializer/deserializer utility function (indeed, I have some suspiciously similar code in my personal projects), but I'm against including it by default in JSONSerializer as it's not a canonical serialization.

You could equally well serialize an Enum by its value, or even its index in definition order.

bmc-msft commented 4 years ago

I rewrote this same feature and came to submit a PR only to find @kitschen already suggested it. A supported utility function would be great.

petered commented 1 year ago

Would be nice to have this included by default. I'd vote for serialising the value rather than the name, as it allows you to refactor without breaking existing serialised files.