Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions serde/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1160,10 +1160,11 @@ def deserialize_enum(typ: type[enum.Enum], value: Any) -> enum.Enum:
# A ValueError/KeyError here means ``typ`` has at least one member (an
# empty enum would raise TypeError instead), so ``__members__`` is never
# empty in this branch.
if isinstance(value, str):
member_value_type = type(next(iter(typ.__members__.values())).value)
if member_value_type is not str:
return typ(member_value_type(value))
member_value_type = type(next(iter(typ.__members__.values())).value)
if isinstance(value, list) and member_value_type is tuple:
return typ(tuple(value))
if isinstance(value, str) and member_value_type is not str:
return typ(member_value_type(value))
raise


Expand Down
36 changes: 36 additions & 0 deletions tests/test_basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,18 +272,54 @@ class IE(enum.IntEnum):
class SE(enum.Enum):
A = "a"

class TE(enum.Enum):
X = ("one", "info one")

# Direct lookup and the str->int coercion both yield the member.
assert deserialize_enum(IE, 1) is IE.V1
assert deserialize_enum(IE, "1") is IE.V1
# A str-valued enum is resolved by the normal lookup (no coercion).
assert deserialize_enum(SE, "a") is SE.A
# A tuple value is serialized as a list
assert deserialize_enum(TE, ["one", "info one"]) is TE.X
# Invalid values re-raise rather than returning None, for every branch:
with pytest.raises((ValueError, KeyError)):
deserialize_enum(IE, 99) # non-str, not a member
with pytest.raises((ValueError, KeyError)):
deserialize_enum(IE, "99") # stringified non-member
with pytest.raises((ValueError, KeyError)):
deserialize_enum(SE, "z") # str-valued enum, invalid
with pytest.raises((ValueError, KeyError)):
deserialize_enum(TE, ["two", "info two"]) # tuple enum, not a member


@pytest.mark.parametrize("se,de", (format_dict + format_json + format_yaml))
def test_enum_with_tuple_value(se: Any, de: Any) -> None:
class TE(enum.Enum):
X = ("one", "info one")
Y = ("two", "info two")

@serde.serde
class C:
m: TE

@serde.serde
class CDict:
m: dict[str, TE]

@serde.serde
class CList:
m: list[TE]

@serde.serde
class COpt:
m: TE | None

assert de(C, se(C(TE.X))) == C(TE.X)
assert de(CDict, se(CDict({"a": TE.X}))) == CDict({"a": TE.X})
assert de(CList, se(CList([TE.X, TE.Y]))) == CList([TE.X, TE.Y])
assert de(COpt, se(COpt(TE.X))) == COpt(TE.X)
assert de(COpt, se(COpt(None))) == COpt(None)


@pytest.mark.parametrize("se,de", (format_dict + format_json + format_yaml))
Expand Down
Loading