I'm getting the following error when I call json() on a dict that contains numpy floats:
return HTTPResponse(json_dumps(body, **kwargs), headers=headers,
OverflowError: Maximum recursion level reached
I'm porting an application from flask to sanic but am stuck there. With flask, I had the following custom JSON encoder:
class CustomJSONEncoder(JSONEncoder):
'''
Custom JSON encoder that converts numpy.float64 values to strings.
'''
def default(self, val):
if isinstance(val, numpy.int32):
return int(val)
if isinstance(val, numpy.int64):
return int(val)
if isinstance(val, numpy.number):
return str(val)
if isinstance(val, numpy.ndarray):
lst = []
for v in val:
lst.append(str(v))
return lst
return JSONEncoder.default(self, val)
I tried json(data, cls=CustomJSONEncoder) but it fails since you're using ujson which doesn't accept a custom encoder class.
Any suggestion on how to best approach this issue?
Using the following work around:
from sanic.response import json as sanic_json
def is_iterable(x):
try:
iter(x)
return True
except TypeError:
return False
def map_anything(x, fn):
if isinstance(x, str):
return fn(x)
if isinstance(x, dict):
return {k: map_anything(v, fn) for k, v in x.items()}
if is_iterable(x):
return [map_anything(ele, fn) for ele in x]
return fn(x)
def prepare_for_json(val):
if isinstance(val, numpy.int32):
return int(val)
if isinstance(val, numpy.int64):
return int(val)
if isinstance(val, numpy.number):
return str(val)
if isinstance(val, numpy.ndarray):
return [str(v) for v in val]
return val
def json(data, **kwargs):
# cls not supported by ujson
# https://github.com/esnme/ultrajson/issues/124
return sanic_json(map_anything(data, prepare_for_json), **kwargs)
The most elegant solution to this is given in the offending line itself. You could create your own json_response, which is essentially a wrapper around HTTPResponse (just like in the first line of your exception).
So something along the lines of:
def json(body, status, headers, content_type):
return HTTPResponse(json.dumps(body), status=status, headers=headers, content_type=content_type)
Configure and use whichever json module you want there, together with your custom encoder.
This should be possible now via https://github.com/channelcat/sanic/pull/948. Please reopen if there is an issue with it.
Most helpful comment
This should be possible now via https://github.com/channelcat/sanic/pull/948. Please reopen if there is an issue with it.