Closed MHajoha closed 1 year ago
Kannst du bitte irgendwo als Kommentar noch etwas genauer beschreiben, wie das funktioniert? Wer sagt dem JSON Encoder, dass der string, den er ausgeben soll, unter
_OptionInfo.value
steht? Oder machtEnum
/EnumMeta
letztendlich aus den_OptionInfo
members Instanzen der eigenen KlasseOptionEnum
?Beim Schreiben des Kommentars wurde mir, glaube ich, klar, dass
def __new__(cls, option: _OptionInfo) -> "OptionEnum": return super().__new__(cls, option.value)
der eigentliche Trick ist, damit der JSON Encoder die Objekte als String betrachtet und den value bekommt, oder?
Genau. Also ein class X(str, Enum)
ist nichts besonderes. Wenn EnumMeta.__new__
dann y = "y"
sieht, ruft es X("y")
(also str("y")) auf. Bei uns steht rechts aber nunmal nicht der Name nochmal als str, sondern ein _OptionInfo
-Objekt. Das schmeißt Python auch in X(_OptionInfo(...))
, aber _OptionInfo
enthielt halt nicht den Member-Namen, der eigentlich der String-Wert werden soll. Deshalb fügt _OptionEnumMeta
den Member-Namen jetzt hinzu, sodass OptionEnum.__new__
ihn an str.__new__
geben kann.
Vielleicht kannst du das Verhalten aber im Code doch noch etwas beschreiben für den Fall, dass wir irgendwann die Klassen wieder anfassen müssen.
Ich habe OptionEnum
's docstring eine Implementation Note
-Sektion hinzugefügt, der das relativ detailliert beschreibt.
Damit
OptionEnum
-Varianten ohne extra JSON encoder als ihre Value serialisiert werden, mussOptionEnum
ein str sein. Um nochlabel
undselected
reinzukriegen, gibtoption()
aber ein_OptionInfo
-Objekt zurück. Das sollte eigentlich nur bis zuOptionEnum.__init__
leben, es stellt sich aber heraus, dassEnumMeta.__new__
sofortstr(_OptionInfo(...))
aufruft, sodass der String-Wert"_OptionInfo(...)"
war und das dann im JSON landete.Um das zu lösen war es letztenendes nötig, die Metaklasse anzufassen. Da wird der
_OptionInfo
der Name hinzugefügt, sodass__new__
ihn verwenden kann.TL;DR: Vorher
"_OptionInfo(label=..., selected=...)"
, jetzt korrekt"OPT_1"
im JSON.