mirror of
https://github.com/getredash/redash.git
synced 2025-12-19 17:37:19 -05:00
Sanitize NaN, Infinite, -Infinite causing error when saving as PostgreSQL JSON #7339 (2nd try) (#7348)
* Sanitize NaN, Infinite, -Infinite causing error when saving as PostgreSQL JSON #7339 (2nd try) * Move json nsanitaize to on the top of json_dumps * Fix comment
This commit is contained in:
@@ -6,6 +6,7 @@ import decimal
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
@@ -120,6 +121,17 @@ def json_loads(data, *args, **kwargs):
|
||||
return json.loads(data, *args, **kwargs)
|
||||
|
||||
|
||||
# Convert NaN, Inf, and -Inf to None, as they are not valid JSON values.
|
||||
def _sanitize_data(data):
|
||||
if isinstance(data, dict):
|
||||
return {k: _sanitize_data(v) for k, v in data.items()}
|
||||
if isinstance(data, list):
|
||||
return [_sanitize_data(v) for v in data]
|
||||
if isinstance(data, float) and (math.isnan(data) or math.isinf(data)):
|
||||
return None
|
||||
return data
|
||||
|
||||
|
||||
def json_dumps(data, *args, **kwargs):
|
||||
"""A custom JSON dumping function which passes all parameters to the
|
||||
json.dumps function."""
|
||||
@@ -128,7 +140,7 @@ def json_dumps(data, *args, **kwargs):
|
||||
# Float value nan or inf in Python should be render to None or null in json.
|
||||
# Using allow_nan = True will make Python render nan as NaN, leading to parse error in front-end
|
||||
kwargs.setdefault("allow_nan", False)
|
||||
return json.dumps(data, *args, **kwargs)
|
||||
return json.dumps(_sanitize_data(data), *args, **kwargs)
|
||||
|
||||
|
||||
def mustache_render(template, context=None, **kwargs):
|
||||
|
||||
31
tests/utils/test_json_dumps.py
Normal file
31
tests/utils/test_json_dumps.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from redash.utils import json_dumps, json_loads
|
||||
from tests import BaseTestCase
|
||||
|
||||
|
||||
class TestJsonDumps(BaseTestCase):
|
||||
"""
|
||||
NaN, Inf, and -Inf are sanitized to None.
|
||||
"""
|
||||
|
||||
def test_data_with_nan_is_sanitized(self):
|
||||
input_data = {
|
||||
"columns": [
|
||||
{"name": "_col0", "friendly_name": "_col0", "type": "float"},
|
||||
{"name": "_col1", "friendly_name": "_col1", "type": "float"},
|
||||
{"name": "_col2", "friendly_name": "_col1", "type": "float"},
|
||||
{"name": "_col3", "friendly_name": "_col1", "type": "float"},
|
||||
],
|
||||
"rows": [{"_col0": 1.0, "_col1": float("nan"), "_col2": float("inf"), "_col3": float("-inf")}],
|
||||
}
|
||||
expected_output_data = {
|
||||
"columns": [
|
||||
{"name": "_col0", "friendly_name": "_col0", "type": "float"},
|
||||
{"name": "_col1", "friendly_name": "_col1", "type": "float"},
|
||||
{"name": "_col2", "friendly_name": "_col1", "type": "float"},
|
||||
{"name": "_col3", "friendly_name": "_col1", "type": "float"},
|
||||
],
|
||||
"rows": [{"_col0": 1.0, "_col1": None, "_col2": None, "_col3": None}],
|
||||
}
|
||||
json_data = json_dumps(input_data)
|
||||
actual_output_data = json_loads(json_data)
|
||||
self.assertEquals(actual_output_data, expected_output_data)
|
||||
Reference in New Issue
Block a user