diff --git a/fiftyone/server/decorators.py b/fiftyone/server/decorators.py index 1d7e434e422..6f013b28944 100644 --- a/fiftyone/server/decorators.py +++ b/fiftyone/server/decorators.py @@ -5,11 +5,14 @@ | `voxel51.com `_ | """ + +from json import JSONEncoder import traceback import typing as t import logging from bson import json_util +import numpy as np from fiftyone.core.utils import run_sync_task @@ -18,6 +21,23 @@ from starlette.requests import Request +class Encoder(JSONEncoder): + def default(self, o): + if isinstance(o, np.floating): + return float(o) + + if isinstance(o, np.integer): + return int(o) + + return JSONEncoder.default(self, o) + + +async def create_response(response: dict): + return Response( + await run_sync_task(lambda: json_util.dumps(response, cls=Encoder)) + ) + + def route(func): async def wrapper( endpoint: HTTPEndpoint, request: Request, *args @@ -30,9 +50,8 @@ async def wrapper( if isinstance(response, Response): return response - return Response( - await run_sync_task(lambda: json_util.dumps(response)) - ) + return await create_response(response) + except Exception as e: logging.exception(e) return JSONResponse( diff --git a/tests/unittests/server_decorators_tests.py b/tests/unittests/server_decorators_tests.py new file mode 100644 index 00000000000..a281ad1a2c3 --- /dev/null +++ b/tests/unittests/server_decorators_tests.py @@ -0,0 +1,32 @@ +""" +FiftyOne Server decorators. + +| Copyright 2017-2024, Voxel51, Inc. +| `voxel51.com `_ +| +""" + +import unittest + +import numpy as np + +from fiftyone.server.decorators import create_response + + +class TestNumPyResponse(unittest.IsolatedAsyncioTestCase): + async def test_numpy_response(self): + await create_response( + { + "float16": np.array([16.0], dtype=np.float16), + "float32": np.array([32.0], dtype=np.float32), + "float64": np.array([64.0], dtype=np.float64), + "int8": np.array([8], dtype=np.int8), + "int16": np.array([8], dtype=np.int16), + "int32": np.array([8], dtype=np.int32), + "int64": np.array([8], dtype=np.int64), + "uint8": np.array([8], dtype=np.uint8), + "uint6": np.array([8], dtype=np.uint16), + "uint32": np.array([8], dtype=np.uint32), + "uint64": np.array([8], dtype=np.uint64), + } + )