diff options
author | robot-piglet <[email protected]> | 2025-01-16 19:09:30 +0300 |
---|---|---|
committer | robot-piglet <[email protected]> | 2025-01-16 19:38:51 +0300 |
commit | 7a23ad1fa2a5561a3575177d7240d8a1aa499718 (patch) | |
tree | b4932bad31f595149e7a42e88cf729919995d735 /contrib/python/Flask/py3/flask/json | |
parent | fbb15f5ab8a61fc7c50500e2757af0b47174d825 (diff) |
Intermediate changes
commit_hash:ae9e37c897fc6d514389f7089184df33bf781005
Diffstat (limited to 'contrib/python/Flask/py3/flask/json')
-rw-r--r-- | contrib/python/Flask/py3/flask/json/__init__.py | 364 | ||||
-rw-r--r-- | contrib/python/Flask/py3/flask/json/provider.py | 310 |
2 files changed, 511 insertions, 163 deletions
diff --git a/contrib/python/Flask/py3/flask/json/__init__.py b/contrib/python/Flask/py3/flask/json/__init__.py index adefe02dcd2..65d8829acbe 100644 --- a/contrib/python/Flask/py3/flask/json/__init__.py +++ b/contrib/python/Flask/py3/flask/json/__init__.py @@ -1,17 +1,14 @@ -import dataclasses -import decimal +from __future__ import annotations + import json as _json import typing as t -import uuid -from datetime import date from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps -from werkzeug.http import http_date from ..globals import current_app -from ..globals import request +from .provider import _default -if t.TYPE_CHECKING: +if t.TYPE_CHECKING: # pragma: no cover from ..app import Flask from ..wrappers import Response @@ -32,23 +29,30 @@ class JSONEncoder(_json.JSONEncoder): 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. """ - if isinstance(o, date): - return http_date(o) - if isinstance(o, (decimal.Decimal, uuid.UUID)): - return str(o) - if dataclasses and dataclasses.is_dataclass(o): - return dataclasses.asdict(o) - if hasattr(o, "__html__"): - return str(o.__html__()) - return super().default(o) + return _default(o) class JSONDecoder(_json.JSONDecoder): @@ -59,144 +63,193 @@ class JSONDecoder(_json.JSONDecoder): Assign a subclass of this to :attr:`flask.Flask.json_decoder` or :attr:`flask.Blueprint.json_decoder` to override the default. - """ - - -def _dump_arg_defaults( - kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None -) -> None: - """Inject default arguments for dump functions.""" - if app is None: - app = current_app - if app: - cls = app.json_encoder - bp = app.blueprints.get(request.blueprint) if request else None # type: ignore - if bp is not None and bp.json_encoder is not None: - cls = bp.json_encoder - - # Only set a custom encoder if it has custom behavior. This is - # faster on PyPy. - if cls is not _json.JSONEncoder: - kwargs.setdefault("cls", cls) - - kwargs.setdefault("cls", cls) - kwargs.setdefault("ensure_ascii", app.config["JSON_AS_ASCII"]) - kwargs.setdefault("sort_keys", app.config["JSON_SORT_KEYS"]) - else: - kwargs.setdefault("sort_keys", True) - kwargs.setdefault("cls", JSONEncoder) + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Use ``app.json`` instead. + """ + def __init__(self, **kwargs) -> None: + import warnings -def _load_arg_defaults( - kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None -) -> None: - """Inject default arguments for load functions.""" - if app is None: - app = current_app + 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) - if app: - cls = app.json_decoder - bp = app.blueprints.get(request.blueprint) if request else None # type: ignore - if bp is not None and bp.json_decoder is not None: - cls = bp.json_decoder - # Only set a custom decoder if it has custom behavior. This is - # faster on PyPy. - if cls not in {JSONDecoder, _json.JSONDecoder}: - kwargs.setdefault("cls", cls) +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() <flask.json.provider.JSONProvider.dumps>` + method, otherwise it will use :func:`json.dumps`. -def dumps(obj: t.Any, app: t.Optional["Flask"] = None, **kwargs: t.Any) -> str: - """Serialize an object to a string of JSON. + :param obj: The data to serialize. + :param kwargs: Arguments passed to the ``dumps`` implementation. - Takes the same arguments as the built-in :func:`json.dumps`, with - some defaults from application configuration. + .. versionchanged:: 2.2 + Calls ``current_app.json.dumps``, allowing an app to override + the behavior. - :param obj: Object to serialize to JSON. - :param app: Use this app's config instead of the active app context - or defaults. - :param kwargs: Extra arguments passed to :func:`json.dumps`. + .. 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`` is deprecated and will be removed in Flask 2.1. + ``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. """ - _dump_arg_defaults(kwargs, app=app) + 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: t.Optional["Flask"] = None, **kwargs: t.Any + obj: t.Any, fp: t.IO[str], *, app: Flask | None = None, **kwargs: t.Any ) -> None: - """Serialize an object to JSON written to a file object. + """Serialize data as JSON and write to a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dump() <flask.json.provider.JSONProvider.dump>` + method, otherwise it will use :func:`json.dump`. - Takes the same arguments as the built-in :func:`json.dump`, with - some defaults from application configuration. + :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. - :param obj: Object to serialize to JSON. - :param fp: File object to write JSON to. - :param app: Use this app's config instead of the active app context - or defaults. - :param kwargs: Extra arguments passed to :func:`json.dump`. + .. 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, is - deprecated and will be removed in Flask 2.1. + Writing to a binary file, and the ``encoding`` argument, will be + removed in Flask 2.1. """ - _dump_arg_defaults(kwargs, app=app) - _json.dump(obj, fp, **kwargs) + 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. -def loads( - s: t.Union[str, bytes], - app: t.Optional["Flask"] = None, - **kwargs: t.Any, -) -> t.Any: - """Deserialize an object from a string of JSON. + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.loads() <flask.json.provider.JSONProvider.loads>` + method, otherwise it will use :func:`json.loads`. - Takes the same arguments as the built-in :func:`json.loads`, with - some defaults from application configuration. + :param s: Text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``loads`` implementation. - :param s: JSON string to deserialize. - :param app: Use this app's config instead of the active app context - or defaults. - :param kwargs: Extra arguments passed to :func:`json.loads`. + .. 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`` is deprecated and will be removed in Flask 2.1. The - data must be a string or UTF-8 bytes. + ``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. """ - _load_arg_defaults(kwargs, app=app) + 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[str], app: t.Optional["Flask"] = None, **kwargs: t.Any) -> t.Any: - """Deserialize an object from JSON read from a file object. +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() <flask.json.provider.JSONProvider.load>` + method, otherwise it will use :func:`json.load`. - Takes the same arguments as the built-in :func:`json.load`, with - some defaults from application configuration. + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``load`` implementation. - :param fp: File object to read JSON from. - :param app: Use this app's config instead of the active app context - or defaults. - :param kwargs: Extra arguments passed to :func:`json.load`. + .. 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`` is deprecated and will be removed in Flask 2.1. The - file must be text mode, or binary mode with UTF-8 bytes. + ``encoding`` will be removed in Flask 2.1. The file must be text + mode, or binary mode with UTF-8 bytes. """ - _load_arg_defaults(kwargs, app=app) + 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) @@ -212,6 +265,9 @@ def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str: double quoted; either use single quotes or the ``|forceescape`` filter. + .. deprecated:: 2.2 + Will be removed in Flask 2.3. This is built-in to Jinja now. + .. versionchanged:: 2.0 Uses :func:`jinja2.utils.htmlsafe_json_dumps`. The returned value is marked safe by wrapping in :class:`~markupsafe.Markup`. @@ -221,6 +277,14 @@ def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str: ``<script>`` tags, and single-quoted attributes without further escaping. """ + import warnings + + warnings.warn( + "'htmlsafe_dumps' is deprecated and will be removed in Flask" + " 2.3. Use 'jinja2.utils.htmlsafe_json_dumps' instead.", + DeprecationWarning, + stacklevel=2, + ) return _jinja_htmlsafe_dumps(obj, dumps=dumps, **kwargs) @@ -228,77 +292,51 @@ def htmlsafe_dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: """Serialize an object to JSON written to a file object, replacing HTML-unsafe characters with Unicode escapes. See :func:`htmlsafe_dumps` and :func:`dumps`. - """ - fp.write(htmlsafe_dumps(obj, **kwargs)) + .. deprecated:: 2.2 + Will be removed in Flask 2.3. + """ + import warnings -def jsonify(*args: t.Any, **kwargs: t.Any) -> "Response": - """Serialize data to JSON and wrap it in a :class:`~flask.Response` - with the :mimetype:`application/json` mimetype. - - Uses :func:`dumps` to serialize the data, but ``args`` and - ``kwargs`` are treated as data rather than arguments to - :func:`json.dumps`. - - 1. Single argument: Treated as a single value. - 2. Multiple arguments: Treated as a list of values. - ``jsonify(1, 2, 3)`` is the same as ``jsonify([1, 2, 3])``. - 3. Keyword arguments: Treated as a dict of values. - ``jsonify(data=data, errors=errors)`` is the same as - ``jsonify({"data": data, "errors": errors})``. - 4. Passing both arguments and keyword arguments is not allowed as - it's not clear what should happen. + warnings.warn( + "'htmlsafe_dump' is deprecated and will be removed in Flask" + " 2.3. Use 'jinja2.utils.htmlsafe_json_dumps' instead.", + DeprecationWarning, + stacklevel=2, + ) + fp.write(htmlsafe_dumps(obj, **kwargs)) - .. code-block:: python - from flask import jsonify +def jsonify(*args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. A dict or list returned from a view will be converted to a + JSON response automatically without needing to call this. - @app.route("/users/me") - def get_current_user(): - return jsonify( - username=g.user.username, - email=g.user.email, - id=g.user.id, - ) + This requires an active request or application context, and calls + :meth:`app.json.response() <flask.json.provider.JSONProvider.response>`. - Will return a JSON response like this: + In debug mode, the output is formatted with indentation to make it + easier to read. This may also be controlled by the provider. - .. code-block:: javascript + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. - { - "username": "admin", - "email": "admin@localhost", - "id": 42 - } + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. - The default output omits indents and spaces after separators. In - debug mode or if :data:`JSONIFY_PRETTYPRINT_REGULAR` is ``True``, - the output will be formatted to be easier to read. + .. versionchanged:: 2.2 + Calls ``current_app.json.response``, allowing an app to override + the behavior. .. versionchanged:: 2.0.2 :class:`decimal.Decimal` is supported by converting to a string. .. versionchanged:: 0.11 - Added support for serializing top-level arrays. This introduces - a security risk in ancient browsers. See :ref:`security-json`. + Added support for serializing top-level arrays. This was a + security risk in ancient browsers. See :ref:`security-json`. .. versionadded:: 0.2 """ - indent = None - separators = (",", ":") - - if current_app.config["JSONIFY_PRETTYPRINT_REGULAR"] or current_app.debug: - indent = 2 - separators = (", ", ": ") - - if args and kwargs: - raise TypeError("jsonify() behavior undefined when passed both args and kwargs") - elif len(args) == 1: # single args are passed directly to dumps() - data = args[0] - else: - data = args or kwargs - - return current_app.response_class( - f"{dumps(data, indent=indent, separators=separators)}\n", - mimetype=current_app.config["JSONIFY_MIMETYPE"], - ) + return current_app.json.response(*args, **kwargs) diff --git a/contrib/python/Flask/py3/flask/json/provider.py b/contrib/python/Flask/py3/flask/json/provider.py new file mode 100644 index 00000000000..cb6aae809be --- /dev/null +++ b/contrib/python/Flask/py3/flask/json/provider.py @@ -0,0 +1,310 @@ +from __future__ import annotations + +import dataclasses +import decimal +import json +import typing as t +import uuid +import weakref +from datetime import date + +from werkzeug.http import http_date + +from ..globals import request + +if t.TYPE_CHECKING: # pragma: no cover + from ..app import Flask + from ..wrappers import Response + + +class JSONProvider: + """A standard set of JSON operations for an application. Subclasses + of this can be used to customize JSON behavior or use different + JSON libraries. + + To implement a provider for a specific library, subclass this base + class and implement at least :meth:`dumps` and :meth:`loads`. All + other methods have default implementations. + + To use a different provider, either subclass ``Flask`` and set + :attr:`~flask.Flask.json_provider_class` to a provider class, or set + :attr:`app.json <flask.Flask.json>` to an instance of the class. + + :param app: An application instance. This will be stored as a + :class:`weakref.proxy` on the :attr:`_app` attribute. + + .. versionadded:: 2.2 + """ + + def __init__(self, app: Flask) -> None: + self._app = weakref.proxy(app) + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + :param obj: The data to serialize. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def dump(self, obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + :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: May be passed to the underlying JSON library. + """ + fp.write(self.dumps(obj, **kwargs)) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + :param s: Text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def load(self, fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + return self.loads(fp.read(), **kwargs) + + def _prepare_response_obj( + self, args: t.Tuple[t.Any, ...], kwargs: t.Dict[str, t.Any] + ) -> t.Any: + if args and kwargs: + raise TypeError("app.json.response() takes either args or kwargs, not both") + + if not args and not kwargs: + return None + + if len(args) == 1: + return args[0] + + return args or kwargs + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. + + The :func:`~flask.json.jsonify` function calls this method for + the current application. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + return self._app.response_class(self.dumps(obj), mimetype="application/json") + + +def _default(o: t.Any) -> t.Any: + if isinstance(o, date): + return http_date(o) + + if isinstance(o, (decimal.Decimal, uuid.UUID)): + return str(o) + + if dataclasses and dataclasses.is_dataclass(o): + return dataclasses.asdict(o) + + if hasattr(o, "__html__"): + return str(o.__html__()) + + raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable") + + +class DefaultJSONProvider(JSONProvider): + """Provide JSON operations using Python's built-in :mod:`json` + library. Serializes the following additional data types: + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :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. + """ + + default: t.Callable[[t.Any], t.Any] = staticmethod( + _default + ) # type: ignore[assignment] + """Apply this function to any object that :meth:`json.dumps` does + not know how to serialize. It should return a valid JSON type or + raise a ``TypeError``. + """ + + ensure_ascii = True + """Replace non-ASCII characters with escape sequences. This may be + more compatible with some clients, but can be disabled for better + performance and size. + """ + + sort_keys = True + """Sort the keys in any serialized dicts. This may be useful for + some caching situations, but can be disabled for better performance. + When enabled, keys must all be strings, they are not converted + before sorting. + """ + + compact: bool | None = None + """If ``True``, or ``None`` out of debug mode, the :meth:`response` + output will not add indentation, newlines, or spaces. If ``False``, + or ``None`` in debug mode, it will use a non-compact representation. + """ + + mimetype = "application/json" + """The mimetype set in :meth:`response`.""" + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON to a string. + + Keyword arguments are passed to :func:`json.dumps`. Sets some + parameter defaults from the :attr:`default`, + :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. + + :param obj: The data to serialize. + :param kwargs: Passed to :func:`json.dumps`. + """ + 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 cls is not None: + import warnings + + warnings.warn( + "Setting 'json_encoder' on the app or a blueprint is" + " deprecated and will be removed in Flask 2.3." + " Customize 'app.json' instead.", + DeprecationWarning, + ) + kwargs.setdefault("cls", cls) + + if "default" not in cls.__dict__: + kwargs.setdefault("default", self.default) + else: + kwargs.setdefault("default", self.default) + + ensure_ascii = self._app.config["JSON_AS_ASCII"] + sort_keys = self._app.config["JSON_SORT_KEYS"] + + if ensure_ascii is not None: + import warnings + + warnings.warn( + "The 'JSON_AS_ASCII' config key is deprecated and will" + " be removed in Flask 2.3. Set 'app.json.ensure_ascii'" + " instead.", + DeprecationWarning, + ) + else: + ensure_ascii = self.ensure_ascii + + if sort_keys is not None: + import warnings + + warnings.warn( + "The 'JSON_SORT_KEYS' config key is deprecated and will" + " be removed in Flask 2.3. Set 'app.json.sort_keys'" + " instead.", + DeprecationWarning, + ) + else: + sort_keys = self.sort_keys + + kwargs.setdefault("ensure_ascii", ensure_ascii) + kwargs.setdefault("sort_keys", sort_keys) + return json.dumps(obj, **kwargs) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON from a string or bytes. + + :param s: Text or UTF-8 bytes. + :param kwargs: Passed to :func:`json.loads`. + """ + 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 cls is not None: + import warnings + + warnings.warn( + "Setting 'json_decoder' on the app or a blueprint is" + " deprecated and will be removed in Flask 2.3." + " Customize 'app.json' instead.", + DeprecationWarning, + ) + kwargs.setdefault("cls", cls) + + return json.loads(s, **kwargs) + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with it. The response mimetype + will be "application/json" and can be changed with + :attr:`mimetype`. + + If :attr:`compact` is ``False`` or debug mode is enabled, the + output will be formatted to be easier to read. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + dump_args: t.Dict[str, t.Any] = {} + pretty = self._app.config["JSONIFY_PRETTYPRINT_REGULAR"] + mimetype = self._app.config["JSONIFY_MIMETYPE"] + + if pretty is not None: + import warnings + + warnings.warn( + "The 'JSONIFY_PRETTYPRINT_REGULAR' config key is" + " deprecated and will be removed in Flask 2.3. Set" + " 'app.json.compact' instead.", + DeprecationWarning, + ) + compact: bool | None = not pretty + else: + compact = self.compact + + if (compact is None and self._app.debug) or compact is False: + dump_args.setdefault("indent", 2) + else: + dump_args.setdefault("separators", (",", ":")) + + if mimetype is not None: + import warnings + + warnings.warn( + "The 'JSONIFY_MIMETYPE' config key is deprecated and" + " will be removed in Flask 2.3. Set 'app.json.mimetype'" + " instead.", + DeprecationWarning, + ) + else: + mimetype = self.mimetype + + return self._app.response_class( + f"{self.dumps(obj, **dump_args)}\n", mimetype=mimetype + ) |