Reputation: 5702
I wrote a custom handler for jsonpickle in order to transform an enum value before serializing the object container.
import jsonpickle
from enum import Enum
class Bar(Enum):
A = 1
B = 2
class Foo:
def __init__(self):
self.hello = 'hello'
self.bar = [Bar.A, Bar.B]
class Handler(jsonpickle.handlers.BaseHandler):
def flatten(self, obj, data): # data contains {}
print(obj)
### How should I handle the enum? ###
return data
jsonpickle.handlers.registry.register(Bar, Handler)
def main():
fizbuz = Foo()
encoded = jsonpickle.encode(fizbuz)
print(encoded)
if __name__ == '__main__':
main()
The handler is called with the obj containing the enum value all right. But then the data dict contains already a key, value pair so I can't just return a single value representing the enum.
So my question is what should be the key, value pair I need to add to the data dict when I am custom-handling elements that return one unique value while I need to fit it in the data dict that has been pre=-populated with reflection data that will be needed for the object to be reconstructed later.
Upvotes: 3
Views: 1841
Reputation: 2976
I don't understand why you're concerned about the dict that is supplied? That is an input for your use to aid in your handler code and doesn't need to be utilized at all if you don't want it. It isn't {}, as you indicated, if you use encode without unpicklable=False. If you don't include that, then you actually get this:
{'py/object': '__main__.Bar'}
All that is providing is the type of the variable and you wrote the handler, so you naturally know the type.
If you want a nice JSON output of your enum, just tell Python that obj of the flatten function is a Bar type (optional, but nice for the IDE and for later maintenance), like this:
def flatten(self, obj: Bar, data):
Then, just return obj.name. Doing this, the output is:
{"py/object": "__main__.Foo", "bar": ["A", "B"], "hello": "hello"}
Of course, we can make it cleaner by telling the encoder not to worry about decoding later with:
unpicklable=False
The final output is then:
{"bar": ["A", "B"], "hello": "hello"}
The whole example code:
import jsonpickle
from enum import Enum
class Bar(Enum):
A = 1
B = 2
class Foo:
def __init__(self):
self.hello = 'hello'
self.bar = [Bar.A, Bar.B]
class Handler(jsonpickle.handlers.BaseHandler):
def flatten(self, obj: Bar, data):
print(obj)
return obj.name
jsonpickle.handlers.registry.register(Bar, Handler)
def main():
fizbuz = Foo()
encoded = jsonpickle.encode(fizbuz, unpicklable=False)
print(encoded)
if __name__ == '__main__':
main()
Generic Approach
You can also generically handle all enums by using a class like this:
from enum import Enum
import jsonpickle
class JsonEnumHandler(jsonpickle.handlers.BaseHandler):
def restore(self, obj):
pass
def flatten(self, obj: Enum, data):
return obj.name
Then, register every enum in your JSON like this:
jsonpickle.handlers.registry.register(LimitType, JsonEnumHandler)
jsonpickle.handlers.registry.register(DeviceType, JsonEnumHandler)
Upvotes: 0