Solution
# model.py
from dataclasses import dataclass, field
from enum import Enum, auto
class GenderEnum(Enum):
p = auto()
l = auto()
@dataclass
class ActivityLevel:
id: int = field(init=False) # NOTE add `repr=False` if trying to display instances
name: str
gender: GenderEnum
# orm.py
from sqlalchemy import Column, Enum, ForeignKey, Integer, String, Table
from sqlalchemy.orm import registry
from .model import ActivityLevel
mapper_registry = registry()
activity_level = Table(
"activity_level",
mapper_registry.metadata,
Column("id", Integer, primary_key=True),
Column("name", String(100), nullable=False),
Column("gender", Enum(GenderEnum), nullable=False),
)
def start_mapper():
mapper_registry.map_imperatively(ActivityLevel, activity_level)
# serialiser.py
from json import JSONDecoder, JSONEncoder
from .model import ActivityLevel, GenderEnum
class ActivityLevelJSONEncoder(JSONEncoder):
def default(self, o):
try: # NOTE duck typing and asking for forgiveness not permission
return {
"name": o.name,
"gender": o.gender.name,
}
except AttributeError:
return super().default(self, o)
class ActivityLevelJSONDecoder(JSONDecoder):
def __init__(self, *args, **kwargs):
super().__init__(*args, object_hook=self._object_hook, **kwargs)
@staticmethod
def _object_hook(d: dict) -> ActivityLevel:
return ActivityLevel(
name=d["name"],
gender=GenderEnum[d["gender"]],
)