From dadd5c1f3a135661786404e5142620445b486e65 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Fri, 7 Jul 2017 12:46:17 -0400 Subject: [PATCH] Add json util wrapper, failing JSONField test --- rest_framework/utils/encoders.py | 2 +- rest_framework/utils/json.py | 33 ++++++++++++++++++++++++++++++++ tests/test_fields.py | 1 + tests/test_utils.py | 21 ++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 rest_framework/utils/json.py diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index 8896e4f2c..a4fe8d0c4 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -1,7 +1,7 @@ """ Helper classes for parsers. """ -from __future__ import unicode_literals +from __future__ import absolute_import, unicode_literals import datetime import decimal diff --git a/rest_framework/utils/json.py b/rest_framework/utils/json.py new file mode 100644 index 000000000..cc7df542e --- /dev/null +++ b/rest_framework/utils/json.py @@ -0,0 +1,33 @@ + +from __future__ import absolute_import + +import functools +import json + + +def strict_constant(o): + raise ValueError('Out of range float values are not JSON compliant: ' + repr(o)) + + +@functools.wraps(json.dump) +def dump(*args, **kwargs): + kwargs.setdefault('allow_nan', False) + return json.dump(*args, **kwargs) + + +@functools.wraps(json.dumps) +def dumps(*args, **kwargs): + kwargs.setdefault('allow_nan', False) + return json.dumps(*args, **kwargs) + + +@functools.wraps(json.load) +def load(*args, **kwargs): + kwargs.setdefault('parse_constant', strict_constant) + return json.load(*args, **kwargs) + + +@functools.wraps(json.loads) +def loads(*args, **kwargs): + kwargs.setdefault('parse_constant', strict_constant) + return json.loads(*args, **kwargs) diff --git a/tests/test_fields.py b/tests/test_fields.py index bb3d349b4..7f7ede2ba 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -1811,6 +1811,7 @@ class TestJSONField(FieldValues): ] invalid_inputs = [ ({'a': set()}, ['Value must be valid JSON.']), + ({'a': float('inf')}, ['Value must be valid JSON.']), ] outputs = [ ({ diff --git a/tests/test_utils.py b/tests/test_utils.py index 11c9e9bb0..9619776d6 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -9,6 +9,7 @@ import rest_framework.utils.model_meta from rest_framework.compat import _resolve_model from rest_framework.routers import SimpleRouter from rest_framework.serializers import ModelSerializer +from rest_framework.utils import json from rest_framework.utils.breadcrumbs import get_breadcrumbs from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet @@ -177,3 +178,23 @@ class ResolveModelWithPatchedDjangoTests(TestCase): def test_blows_up_if_model_does_not_resolve(self): with self.assertRaises(ImproperlyConfigured): _resolve_model('tests.BasicModel') + + +class JsonFloatTests(TestCase): + """ + Internaly, wrapped json functions should adhere to strict float handling + """ + + def test_dumps(self): + with self.assertRaises(ValueError): + json.dumps(float('inf')) + + with self.assertRaises(ValueError): + json.dumps(float('nan')) + + def test_loads(self): + with self.assertRaises(ValueError): + json.loads("Infinity") + + with self.assertRaises(ValueError): + json.loads("NaN")