As far as I understood, there's no way to define a custom JSON encoder for SocketIO, so that it overrides the default one.
I saw that it is possible to provide a complete json package as a replacement for Python's default one, but it seems a bit overkill if one simply wants to define how to encode some non-serilizable type.
Oh looks like this is a documentation bug. You can pass a json argument with your favorite json implementation. It is one of the lower level engine.io options, it is documented in the engine.io package (here) but looks like I missed it in the main package docs.
Actually I think that is documented in flask-socketio (https://github.com/miguelgrinberg/Flask-SocketIO/blob/master/flask_socketio/__init__.py#L76). But this is what I meant when I said it seems a bit overkill as I don't want to change the json implementation, just its encoder.
Could it be possible for the SocketIO object to use the json encoder defined in the Flask app for instance?
Ah right, so it is documented as a socketio option, but it should be in the engineio section as that is where this is implemented.
In any case, just pass the Flask json module if that's what you want to use. Add from flask import json and then pass json=json as an argument to SocketIO.
Thanks for the quick answers! Obviously I fail to make myself clear.
What I would've wanted is to pass a subclass of JSONEncoder to the SocketIO instance, so that it could encode my custom objects, in the same fashion as I would do it with Flask. For instance:
from flask import Flask
from flask.json import JSONEncoder
class MyAwesomeEncoder(JSONEncoder):
def default(self, object_):
...
app = Flask(__name__)
app.json_encoder = MyAwesomeEncoder
That way, I wouldn't have to write a complete json module, just to handle a handful of objects in my encoder. I can create a module that just forwards everything to Python's json implementation (or any other) and simply redefine loads and dumps to use my custom encoder. But it feels cumbersome to me, and less flexible than passing a subclass.
That said, digging in your code I feel like I should have opened this issue on engine.io rather than here. In particular, this feature would be implemented by the Packet class so that this line would rather look this:
encoded_packet += self.json.dumps(self.data, separators=(',', ':'), cls=self.json_encoder)
Coming back to flask-socketio, it would be awesome if the self.json_encoder in the above line was pointing to the app.json_encoder we would have read in SocketIO.init_app.
By the way, the same argument could be made for the decoder at this line.
I think I do understand what you are asking. If you pass flask.json in the json argument as I suggested, then any custom encoder or decoder you added to your Flask app will be used.
Do you want to use a custom JSON encoder that is not the same as what you are using in your Flask app, or maybe you don't have a Flask app at all? That's the only situation in which you would need to create a wrapper for the original json package.
If you wanted to override the default encoder or decoder, then all you need to do is write a module or class with two functions or methods dumps and loads. Maybe something like this:
import json
class MyAwesomeJsonWrapper(object):
@staticmethod
def dumps(*args, **kwargs):
if 'cls' not in kwargs:
kwargs['cls'] = MyAwesomeEncoder
return json.dumps(*args, **kwargs)
@staticmethod
def loads(*args, **kwargs):
return json.loads(*args, **kwargs)
So it really isn't a lot of code that you need to write.
Alright, thanks! Sorry I didn't think setting the JSON encoder on the flask application would actually change the class that gets loaded by flask.json.
Maybe it is worth adding in the documentation as well.
Most helpful comment
I think I do understand what you are asking. If you pass
flask.jsonin thejsonargument as I suggested, then any custom encoder or decoder you added to your Flask app will be used.Do you want to use a custom JSON encoder that is not the same as what you are using in your Flask app, or maybe you don't have a Flask app at all? That's the only situation in which you would need to create a wrapper for the original
jsonpackage.If you wanted to override the default encoder or decoder, then all you need to do is write a module or class with two functions or methods
dumpsandloads. Maybe something like this:So it really isn't a lot of code that you need to write.