Serialising an Enum member to JSON
I know this is old but I feel this will help people. I just went through this exact problem and discovered if you're using string enums, declaring your enums as a subclass of str
works well for almost all situations:
import jsonfrom enum import Enumclass LogLevel(str, Enum): DEBUG = 'DEBUG' INFO = 'INFO'print(LogLevel.DEBUG)print(json.dumps(LogLevel.DEBUG))print(json.loads('"DEBUG"'))print(LogLevel('DEBUG'))
Will output:
LogLevel.DEBUG"DEBUG"DEBUGLogLevel.DEBUG
As you can see, loading the JSON outputs the string DEBUG
but it is easily castable back into a LogLevel object. A good option if you don't want to create a custom JSONEncoder.
The correct answer depends on what you intend to do with the serialized version.
If you are going to unserialize back into Python, see Zero's answer.
If your serialized version is going to another language then you probably want to use an IntEnum
instead, which is automatically serialized as the corresponding integer:
from enum import IntEnumimport jsonclass Status(IntEnum): success = 0 failure = 1json.dumps(Status.success)
and this returns:
'0'
If you want to encode an arbitrary enum.Enum
member to JSON and then decodeit as the same enum member (rather than simply the enum member's value
attribute), you can do so by writing a custom JSONEncoder
class, and a decoding function to pass as the object_hook
argument to json.load()
or json.loads()
:
PUBLIC_ENUMS = { 'Status': Status, # ...}class EnumEncoder(json.JSONEncoder): def default(self, obj): if type(obj) in PUBLIC_ENUMS.values(): return {"__enum__": str(obj)} return json.JSONEncoder.default(self, obj)def as_enum(d): if "__enum__" in d: name, member = d["__enum__"].split(".") return getattr(PUBLIC_ENUMS[name], member) else: return d
The as_enum
function relies on the JSON having been encoded using EnumEncoder
, or something which behaves identically to it.
The restriction to members of PUBLIC_ENUMS
is necessary to avoid a maliciously crafted text being used to, for example, trick calling code into saving private information (e.g. a secret key used by the application) to an unrelated database field, from where it could then be exposed (see https://chat.stackoverflow.com/transcript/message/35999686#35999686).
Example usage:
>>> data = {... "action": "frobnicate",... "status": Status.success... }>>> text = json.dumps(data, cls=EnumEncoder)>>> text'{"status": {"__enum__": "Status.success"}, "action": "frobnicate"}'>>> json.loads(text, object_hook=as_enum){'status': <Status.success: 0>, 'action': 'frobnicate'}