from __future__ import annotations import json as _json import typing as t from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps from ..globals import current_app from .provider import _default if t.TYPE_CHECKING: # pragma: no cover from ..app import Flask from ..wrappers import Response class JSONEncoder(_json.JSONEncoder): """The default JSON encoder. Handles extra types compared to the built-in :class:`json.JSONEncoder`. - :class:`datetime.datetime` and :class:`datetime.date` are serialized to :rfc:`822` strings. This is the same as the HTTP date format. - :class:`decimal.Decimal` is serialized to a string. - :class:`uuid.UUID` is serialized to a string. - :class:`dataclasses.dataclass` is passed to :func:`dataclasses.asdict`. - :class:`~markupsafe.Markup` (or any object with a ``__html__`` method) will call the ``__html__`` method to get a string. Assign a subclass of this to :attr:`flask.Flask.json_encoder` or :attr:`flask.Blueprint.json_encoder` to override the default. .. deprecated:: 2.2 Will be removed in Flask 2.3. Use ``app.json`` instead. """ def __init__(self, **kwargs) -> None: import warnings warnings.warn( "'JSONEncoder' is deprecated and will be removed in" " Flask 2.3. Use 'Flask.json' to provide an alternate" " JSON implementation instead.", DeprecationWarning, stacklevel=3, ) super().__init__(**kwargs) def default(self, o: t.Any) -> t.Any: """Convert ``o`` to a JSON serializable type. See :meth:`json.JSONEncoder.default`. Python does not support overriding how basic types like ``str`` or ``list`` are serialized, they are handled before this method. """ return _default(o) class JSONDecoder(_json.JSONDecoder): """The default JSON decoder. This does not change any behavior from the built-in :class:`json.JSONDecoder`. Assign a subclass of this to :attr:`flask.Flask.json_decoder` or :attr:`flask.Blueprint.json_decoder` to override the default. .. deprecated:: 2.2 Will be removed in Flask 2.3. Use ``app.json`` instead. """ def __init__(self, **kwargs) -> None: import warnings warnings.warn( "'JSONDecoder' is deprecated and will be removed in" " Flask 2.3. Use 'Flask.json' to provide an alternate" " JSON implementation instead.", DeprecationWarning, stacklevel=3, ) super().__init__(**kwargs) def dumps(obj: t.Any, *, app: Flask | None = None, **kwargs: t.Any) -> str: """Serialize data as JSON. If :data:`~flask.current_app` is available, it will use its :meth:`app.json.dumps() ` method, otherwise it will use :func:`json.dumps`. :param obj: The data to serialize. :param kwargs: Arguments passed to the ``dumps`` implementation. .. versionchanged:: 2.2 Calls ``current_app.json.dumps``, allowing an app to override the behavior. .. versionchanged:: 2.2 The ``app`` parameter will be removed in Flask 2.3. .. versionchanged:: 2.0.2 :class:`decimal.Decimal` is supported by converting to a string. .. versionchanged:: 2.0 ``encoding`` will be removed in Flask 2.1. .. versionchanged:: 1.0.3 ``app`` can be passed directly, rather than requiring an app context for configuration. """ if app is not None: import warnings warnings.warn( "The 'app' parameter is deprecated and will be removed in" " Flask 2.3. Call 'app.json.dumps' directly instead.", DeprecationWarning, stacklevel=2, ) else: app = current_app if app: return app.json.dumps(obj, **kwargs) kwargs.setdefault("default", _default) return _json.dumps(obj, **kwargs) def dump( obj: t.Any, fp: t.IO[str], *, app: Flask | None = None, **kwargs: t.Any ) -> None: """Serialize data as JSON and write to a file. If :data:`~flask.current_app` is available, it will use its :meth:`app.json.dump() ` method, otherwise it will use :func:`json.dump`. :param obj: The data to serialize. :param fp: A file opened for writing text. Should use the UTF-8 encoding to be valid JSON. :param kwargs: Arguments passed to the ``dump`` implementation. .. versionchanged:: 2.2 Calls ``current_app.json.dump``, allowing an app to override the behavior. .. versionchanged:: 2.2 The ``app`` parameter will be removed in Flask 2.3. .. versionchanged:: 2.0 Writing to a binary file, and the ``encoding`` argument, will be removed in Flask 2.1. """ if app is not None: import warnings warnings.warn( "The 'app' parameter is deprecated and will be removed in" " Flask 2.3. Call 'app.json.dump' directly instead.", DeprecationWarning, stacklevel=2, ) else: app = current_app if app: app.json.dump(obj, fp, **kwargs) else: kwargs.setdefault("default", _default) _json.dump(obj, fp, **kwargs) def loads(s: str | bytes, *, app: Flask | None = None, **kwargs: t.Any) -> t.Any: """Deserialize data as JSON. If :data:`~flask.current_app` is available, it will use its :meth:`app.json.loads() ` method, otherwise it will use :func:`json.loads`. :param s: Text or UTF-8 bytes. :param kwargs: Arguments passed to the ``loads`` implementation. .. versionchanged:: 2.2 Calls ``current_app.json.loads``, allowing an app to override the behavior. .. versionchanged:: 2.2 The ``app`` parameter will be removed in Flask 2.3. .. versionchanged:: 2.0 ``encoding`` will be removed in Flask 2.1. The data must be a string or UTF-8 bytes. .. versionchanged:: 1.0.3 ``app`` can be passed directly, rather than requiring an app context for configuration. """ if app is not None: import warnings warnings.warn( "The 'app' parameter is deprecated and will be removed in" " Flask 2.3. Call 'app.json.loads' directly instead.", DeprecationWarning, stacklevel=2, ) else: app = current_app if app: return app.json.loads(s, **kwargs) return _json.loads(s, **kwargs) def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **kwargs: t.Any) -> t.Any: """Deserialize data as JSON read from a file. If :data:`~flask.current_app` is available, it will use its :meth:`app.json.load() ` method, otherwise it will use :func:`json.load`. :param fp: A file opened for reading text or UTF-8 bytes. :param kwargs: Arguments passed to the ``load`` implementation. .. versionchanged:: 2.2 Calls ``current_app.json.load``, allowing an app to override the behavior. .. versionchanged:: 2.2 The ``app`` parameter will be removed in Flask 2.3. .. versionchanged:: 2.0 ``encoding`` will be removed in Flask 2.1. The file must be text mode, or binary mode with UTF-8 bytes. """ if app is not None: import warnings warnings.warn( "The 'app' parameter is deprecated and will be removed in" " Flask 2.3. Call 'app.json.load' directly instead.", DeprecationWarning, stacklevel=2, ) else: app = current_app if app: return app.json.load(fp, **kwargs) return _json.load(fp, **kwargs) def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str: """Serialize an object to a string of JSON with :func:`dumps`, then replace HTML-unsafe characters with Unicode escapes and mark the result safe with :class:`~markupsafe.Markup`. This is available in templates as the ``|tojson`` filter. The returned string is safe to render in HTML documents and ``