Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Version 2.2.1

Unreleased

- Setting or accessing ``json_encoder`` or ``json_decoder`` raises a
deprecation warning. :issue:`4732`


Version 2.2.0
-------------
Expand Down Expand Up @@ -50,18 +53,18 @@ Released 2022-08-01
provider can be set to use a different JSON library.
``flask.jsonify`` will call ``app.json.response``, other
functions in ``flask.json`` will call corresponding functions in
``app.json``. :pr:`4688`
``app.json``. :pr:`4692`

- JSON configuration is moved to attributes on the default
``app.json`` provider. ``JSON_AS_ASCII``, ``JSON_SORT_KEYS``,
``JSONIFY_MIMETYPE``, and ``JSONIFY_PRETTYPRINT_REGULAR`` are
deprecated. :pr:`4688`
deprecated. :pr:`4692`
- Setting custom ``json_encoder`` and ``json_decoder`` classes on the
app or a blueprint, and the corresponding ``json.JSONEncoder`` and
``JSONDecoder`` classes, are deprecated. JSON behavior can now be
overridden using the ``app.json`` provider interface. :pr:`4688`
overridden using the ``app.json`` provider interface. :pr:`4692`
- ``json.htmlsafe_dumps`` and ``json.htmlsafe_dump`` are deprecated,
the function is built-in to Jinja now. :pr:`4688`
the function is built-in to Jinja now. :pr:`4692`
- Refactor ``register_error_handler`` to consolidate error checking.
Rewrite some error messages to be more consistent. :issue:`4559`
- Use Blueprint decorators and functions intended for setup after
Expand Down
98 changes: 80 additions & 18 deletions src/flask/app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import functools
import inspect
import json
import logging
import os
import sys
Expand Down Expand Up @@ -379,25 +380,86 @@ def use_x_sendfile(self, value: bool) -> None:
)
self.config["USE_X_SENDFILE"] = value

#: The JSON encoder class to use. Defaults to
#: :class:`~flask.json.JSONEncoder`.
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3. Customize
#: :attr:`json_provider_class` instead.
#:
#: .. versionadded:: 0.10
json_encoder: None = None
_json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None
_json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None

#: The JSON decoder class to use. Defaults to
#: :class:`~flask.json.JSONDecoder`.
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3. Customize
#: :attr:`json_provider_class` instead.
#:
#: .. versionadded:: 0.10
json_decoder: None = None
@property # type: ignore[override]
def json_encoder(self) -> t.Type[json.JSONEncoder]: # type: ignore[override]
"""The JSON encoder class to use. Defaults to
:class:`~flask.json.JSONEncoder`.

.. deprecated:: 2.2
Will be removed in Flask 2.3. Customize
:attr:`json_provider_class` instead.

.. versionadded:: 0.10
"""
import warnings

warnings.warn(
"'app.json_encoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)

if self._json_encoder is None:
from . import json

return json.JSONEncoder

return self._json_encoder

@json_encoder.setter
def json_encoder(self, value: t.Type[json.JSONEncoder]) -> None:
import warnings

warnings.warn(
"'app.json_encoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
self._json_encoder = value

@property # type: ignore[override]
def json_decoder(self) -> t.Type[json.JSONDecoder]: # type: ignore[override]
"""The JSON decoder class to use. Defaults to
:class:`~flask.json.JSONDecoder`.

.. deprecated:: 2.2
Will be removed in Flask 2.3. Customize
:attr:`json_provider_class` instead.

.. versionadded:: 0.10
"""
import warnings

warnings.warn(
"'app.json_decoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)

if self._json_decoder is None:
from . import json

return json.JSONDecoder

return self._json_decoder

@json_decoder.setter
def json_decoder(self, value: t.Type[json.JSONDecoder]) -> None:
import warnings

warnings.warn(
"'app.json_decoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
self._json_decoder = value

json_provider_class: t.Type[JSONProvider] = DefaultJSONProvider
"""A subclass of :class:`~flask.json.provider.JSONProvider`. An
Expand Down
83 changes: 71 additions & 12 deletions src/flask/blueprints.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
import os
import typing as t
from collections import defaultdict
Expand Down Expand Up @@ -172,18 +173,76 @@ class Blueprint(Scaffold):

_got_registered_once = False

#: Blueprint local JSON encoder class to use. Set to ``None`` to use
#: the app's :class:`~flask.Flask.json_encoder`.
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3.
json_encoder: None = None
#: Blueprint local JSON decoder class to use. Set to ``None`` to use
#: the app's :class:`~flask.Flask.json_decoder`.
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3.
json_decoder: None = None
_json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None
_json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None

@property # type: ignore[override]
def json_encoder( # type: ignore[override]
self,
) -> t.Union[t.Type[json.JSONEncoder], None]:
"""Blueprint-local JSON encoder class to use. Set to ``None`` to use the app's.

.. deprecated:: 2.2
Will be removed in Flask 2.3. Customize
:attr:`json_provider_class` instead.

.. versionadded:: 0.10
"""
import warnings

warnings.warn(
"'bp.json_encoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
return self._json_encoder

@json_encoder.setter
def json_encoder(self, value: t.Union[t.Type[json.JSONEncoder], None]) -> None:
import warnings

warnings.warn(
"'bp.json_encoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
self._json_encoder = value

@property # type: ignore[override]
def json_decoder( # type: ignore[override]
self,
) -> t.Union[t.Type[json.JSONDecoder], None]:
"""Blueprint-local JSON decoder class to use. Set to ``None`` to use the app's.

.. deprecated:: 2.2
Will be removed in Flask 2.3. Customize
:attr:`json_provider_class` instead.

.. versionadded:: 0.10
"""
import warnings

warnings.warn(
"'bp.json_decoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
return self._json_decoder

@json_decoder.setter
def json_decoder(self, value: t.Union[t.Type[json.JSONDecoder], None]) -> None:
import warnings

warnings.warn(
"'bp.json_decoder' is deprecated and will be removed in Flask 2.3."
" Customize 'app.json_provider_class' or 'app.json' instead.",
DeprecationWarning,
stacklevel=2,
)
self._json_decoder = value

def __init__(
self,
Expand Down
12 changes: 6 additions & 6 deletions src/flask/json/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,11 @@ def dumps(self, obj: t.Any, **kwargs: t.Any) -> str:
:param obj: The data to serialize.
:param kwargs: Passed to :func:`json.dumps`.
"""
cls = self._app.json_encoder
cls = self._app._json_encoder
bp = self._app.blueprints.get(request.blueprint) if request else None

if bp is not None and bp.json_encoder is not None:
cls = bp.json_encoder
if bp is not None and bp._json_encoder is not None:
cls = bp._json_encoder

if cls is not None:
import warnings
Expand Down Expand Up @@ -235,11 +235,11 @@ def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any:
:param s: Text or UTF-8 bytes.
:param kwargs: Passed to :func:`json.loads`.
"""
cls = self._app.json_decoder
cls = self._app._json_decoder
bp = self._app.blueprints.get(request.blueprint) if request else None

if bp is not None and bp.json_decoder is not None:
cls = bp.json_decoder
if bp is not None and bp._json_decoder is not None:
cls = bp._json_decoder

if cls is not None:
import warnings
Expand Down
5 changes: 3 additions & 2 deletions src/flask/scaffold.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import importlib.util
import json
import os
import pathlib
import pkgutil
Expand Down Expand Up @@ -78,14 +79,14 @@ class Scaffold:
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3.
json_encoder: None = None
json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None

#: JSON decoder class used by :func:`flask.json.loads`. If a
#: blueprint sets this, it will be used instead of the app's value.
#:
#: .. deprecated:: 2.2
#: Will be removed in Flask 2.3.
json_decoder: None = None
json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None

def __init__(
self,
Expand Down