diff --git a/backend/handler/socket_handler.py b/backend/handler/socket_handler.py index a3392fb14..ac274c508 100644 --- a/backend/handler/socket_handler.py +++ b/backend/handler/socket_handler.py @@ -1,5 +1,6 @@ import socketio # type: ignore from config import REDIS_URL +from utils import json as json_module class SocketHandler: @@ -7,6 +8,7 @@ class SocketHandler: self.socket_server = socketio.AsyncServer( cors_allowed_origins="*", async_mode="asgi", + json=json_module, logger=False, engineio_logger=False, client_manager=socketio.AsyncRedisManager(str(REDIS_URL)), diff --git a/backend/utils/json.py b/backend/utils/json.py new file mode 100644 index 000000000..5d537b22a --- /dev/null +++ b/backend/utils/json.py @@ -0,0 +1,29 @@ +"""JSON-compatible module with sane defaults. + +Inspiration taken from `python-engineio`. +https://github.com/miguelgrinberg/python-engineio/blob/main/src/engineio/json.py +""" + +import datetime +import decimal +import json +import uuid +from json import * # noqa: F401, F403 +from json import dumps as __original_dumps +from typing import Any + + +class DefaultJSONEncoder(json.JSONEncoder): + """Custom JSON encoder that supports encoding additional types.""" + + def default(self, o: Any) -> Any: + if isinstance(o, (datetime.date, datetime.datetime, datetime.time)): + return o.isoformat() + if isinstance(o, (decimal.Decimal, uuid.UUID)): + return str(o) + return super().default(o) + + +def dumps(*args: Any, **kwargs: Any) -> str: # type: ignore[no-redef] + kwargs.setdefault("cls", DefaultJSONEncoder) + return __original_dumps(*args, **kwargs)