diff --git a/CHANGES.rst b/CHANGES.rst index 232b144a5c..71d327bbfc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -28,6 +28,9 @@ Unreleased it's disabled in config. Previously, only disabling worked. :issue:`5916` - ``Flask.select_jinja_autoescape`` uses case-insensitive comparison instead of only lower case file extensions. :pr:`6012` +- Add ``allow_nan`` attribute to ``DefaultJSONProvider`` to control whether + ``NaN`` and ``Infinity`` values are allowed when serializing to JSON. + Defaults to ``True`` to preserve existing behavior. :issue:`6114` Version 3.1.3 diff --git a/src/flask/json/provider.py b/src/flask/json/provider.py index f37cb7b209..71756d8951 100644 --- a/src/flask/json/provider.py +++ b/src/flask/json/provider.py @@ -160,6 +160,15 @@ class DefaultJSONProvider(JSONProvider): or ``None`` in debug mode, it will use a non-compact representation. """ + allow_nan = True + """Allow ``NaN``, ``Infinity``, and ``-Infinity`` to be serialized as + the bare literals ``NaN``, ``Infinity``, and ``-Infinity``. These are + accepted by Python's :mod:`json` but are not valid JSON per + :rfc:`8259`, so strict parsers such as a browser's ``JSON.parse`` + will reject them. Set this to ``False`` to raise a ``ValueError`` + instead when such a value is serialized. + """ + mimetype = "application/json" """The mimetype set in :meth:`response`.""" @@ -168,7 +177,8 @@ def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: Keyword arguments are passed to :func:`json.dumps`. Sets some parameter defaults from the :attr:`default`, - :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. + :attr:`ensure_ascii`, :attr:`sort_keys`, and :attr:`allow_nan` + attributes. :param obj: The data to serialize. :param kwargs: Passed to :func:`json.dumps`. @@ -176,6 +186,7 @@ def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: kwargs.setdefault("default", self.default) kwargs.setdefault("ensure_ascii", self.ensure_ascii) kwargs.setdefault("sort_keys", self.sort_keys) + kwargs.setdefault("allow_nan", self.allow_nan) return json.dumps(obj, **kwargs) def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: diff --git a/tests/test_json.py b/tests/test_json.py index 1e2b27dc9c..11af91f9ec 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -54,6 +54,16 @@ def test_json_as_unicode(test_value, expected, app, app_ctx): assert rv == expected +def test_json_allow_nan(app, app_ctx): + assert app.json.allow_nan + rv = app.json.dumps(float("nan")) + assert rv == "NaN" + + app.json.allow_nan = False + with pytest.raises(ValueError): + app.json.dumps(float("nan")) + + def test_json_dump_to_file(app, app_ctx): test_data = {"name": "Flask"} out = io.StringIO()