Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/flask/json/__init__.py: 29%
78 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:03 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:03 +0000
1import dataclasses
2import decimal
3import json as _json
4import typing as t
5import uuid
6from datetime import date
8from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps
9from werkzeug.http import http_date
11from ..globals import current_app
12from ..globals import request
14if t.TYPE_CHECKING:
15 from ..app import Flask
16 from ..wrappers import Response
19class JSONEncoder(_json.JSONEncoder):
20 """The default JSON encoder. Handles extra types compared to the
21 built-in :class:`json.JSONEncoder`.
23 - :class:`datetime.datetime` and :class:`datetime.date` are
24 serialized to :rfc:`822` strings. This is the same as the HTTP
25 date format.
26 - :class:`decimal.Decimal` is serialized to a string.
27 - :class:`uuid.UUID` is serialized to a string.
28 - :class:`dataclasses.dataclass` is passed to
29 :func:`dataclasses.asdict`.
30 - :class:`~markupsafe.Markup` (or any object with a ``__html__``
31 method) will call the ``__html__`` method to get a string.
33 Assign a subclass of this to :attr:`flask.Flask.json_encoder` or
34 :attr:`flask.Blueprint.json_encoder` to override the default.
35 """
37 def default(self, o: t.Any) -> t.Any:
38 """Convert ``o`` to a JSON serializable type. See
39 :meth:`json.JSONEncoder.default`. Python does not support
40 overriding how basic types like ``str`` or ``list`` are
41 serialized, they are handled before this method.
42 """
43 if isinstance(o, date):
44 return http_date(o)
45 if isinstance(o, (decimal.Decimal, uuid.UUID)):
46 return str(o)
47 if dataclasses and dataclasses.is_dataclass(o):
48 return dataclasses.asdict(o)
49 if hasattr(o, "__html__"):
50 return str(o.__html__())
51 return super().default(o)
54class JSONDecoder(_json.JSONDecoder):
55 """The default JSON decoder.
57 This does not change any behavior from the built-in
58 :class:`json.JSONDecoder`.
60 Assign a subclass of this to :attr:`flask.Flask.json_decoder` or
61 :attr:`flask.Blueprint.json_decoder` to override the default.
62 """
65def _dump_arg_defaults(
66 kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None
67) -> None:
68 """Inject default arguments for dump functions."""
69 if app is None:
70 app = current_app
72 if app:
73 cls = app.json_encoder
74 bp = app.blueprints.get(request.blueprint) if request else None # type: ignore
75 if bp is not None and bp.json_encoder is not None:
76 cls = bp.json_encoder
78 # Only set a custom encoder if it has custom behavior. This is
79 # faster on PyPy.
80 if cls is not _json.JSONEncoder:
81 kwargs.setdefault("cls", cls)
83 kwargs.setdefault("cls", cls)
84 kwargs.setdefault("ensure_ascii", app.config["JSON_AS_ASCII"])
85 kwargs.setdefault("sort_keys", app.config["JSON_SORT_KEYS"])
86 else:
87 kwargs.setdefault("sort_keys", True)
88 kwargs.setdefault("cls", JSONEncoder)
91def _load_arg_defaults(
92 kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None
93) -> None:
94 """Inject default arguments for load functions."""
95 if app is None:
96 app = current_app
98 if app:
99 cls = app.json_decoder
100 bp = app.blueprints.get(request.blueprint) if request else None # type: ignore
101 if bp is not None and bp.json_decoder is not None:
102 cls = bp.json_decoder
104 # Only set a custom decoder if it has custom behavior. This is
105 # faster on PyPy.
106 if cls not in {JSONDecoder, _json.JSONDecoder}:
107 kwargs.setdefault("cls", cls)
110def dumps(obj: t.Any, app: t.Optional["Flask"] = None, **kwargs: t.Any) -> str:
111 """Serialize an object to a string of JSON.
113 Takes the same arguments as the built-in :func:`json.dumps`, with
114 some defaults from application configuration.
116 :param obj: Object to serialize to JSON.
117 :param app: Use this app's config instead of the active app context
118 or defaults.
119 :param kwargs: Extra arguments passed to :func:`json.dumps`.
121 .. versionchanged:: 2.0.2
122 :class:`decimal.Decimal` is supported by converting to a string.
124 .. versionchanged:: 2.0
125 ``encoding`` is deprecated and will be removed in Flask 2.1.
127 .. versionchanged:: 1.0.3
128 ``app`` can be passed directly, rather than requiring an app
129 context for configuration.
130 """
131 _dump_arg_defaults(kwargs, app=app)
132 return _json.dumps(obj, **kwargs)
135def dump(
136 obj: t.Any, fp: t.IO[str], app: t.Optional["Flask"] = None, **kwargs: t.Any
137) -> None:
138 """Serialize an object to JSON written to a file object.
140 Takes the same arguments as the built-in :func:`json.dump`, with
141 some defaults from application configuration.
143 :param obj: Object to serialize to JSON.
144 :param fp: File object to write JSON to.
145 :param app: Use this app's config instead of the active app context
146 or defaults.
147 :param kwargs: Extra arguments passed to :func:`json.dump`.
149 .. versionchanged:: 2.0
150 Writing to a binary file, and the ``encoding`` argument, is
151 deprecated and will be removed in Flask 2.1.
152 """
153 _dump_arg_defaults(kwargs, app=app)
154 _json.dump(obj, fp, **kwargs)
157def loads(
158 s: t.Union[str, bytes],
159 app: t.Optional["Flask"] = None,
160 **kwargs: t.Any,
161) -> t.Any:
162 """Deserialize an object from a string of JSON.
164 Takes the same arguments as the built-in :func:`json.loads`, with
165 some defaults from application configuration.
167 :param s: JSON string to deserialize.
168 :param app: Use this app's config instead of the active app context
169 or defaults.
170 :param kwargs: Extra arguments passed to :func:`json.loads`.
172 .. versionchanged:: 2.0
173 ``encoding`` is deprecated and will be removed in Flask 2.1. The
174 data must be a string or UTF-8 bytes.
176 .. versionchanged:: 1.0.3
177 ``app`` can be passed directly, rather than requiring an app
178 context for configuration.
179 """
180 _load_arg_defaults(kwargs, app=app)
181 return _json.loads(s, **kwargs)
184def load(fp: t.IO[str], app: t.Optional["Flask"] = None, **kwargs: t.Any) -> t.Any:
185 """Deserialize an object from JSON read from a file object.
187 Takes the same arguments as the built-in :func:`json.load`, with
188 some defaults from application configuration.
190 :param fp: File object to read JSON from.
191 :param app: Use this app's config instead of the active app context
192 or defaults.
193 :param kwargs: Extra arguments passed to :func:`json.load`.
195 .. versionchanged:: 2.0
196 ``encoding`` is deprecated and will be removed in Flask 2.1. The
197 file must be text mode, or binary mode with UTF-8 bytes.
198 """
199 _load_arg_defaults(kwargs, app=app)
200 return _json.load(fp, **kwargs)
203def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str:
204 """Serialize an object to a string of JSON with :func:`dumps`, then
205 replace HTML-unsafe characters with Unicode escapes and mark the
206 result safe with :class:`~markupsafe.Markup`.
208 This is available in templates as the ``|tojson`` filter.
210 The returned string is safe to render in HTML documents and
211 ``<script>`` tags. The exception is in HTML attributes that are
212 double quoted; either use single quotes or the ``|forceescape``
213 filter.
215 .. versionchanged:: 2.0
216 Uses :func:`jinja2.utils.htmlsafe_json_dumps`. The returned
217 value is marked safe by wrapping in :class:`~markupsafe.Markup`.
219 .. versionchanged:: 0.10
220 Single quotes are escaped, making this safe to use in HTML,
221 ``<script>`` tags, and single-quoted attributes without further
222 escaping.
223 """
224 return _jinja_htmlsafe_dumps(obj, dumps=dumps, **kwargs)
227def htmlsafe_dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None:
228 """Serialize an object to JSON written to a file object, replacing
229 HTML-unsafe characters with Unicode escapes. See
230 :func:`htmlsafe_dumps` and :func:`dumps`.
231 """
232 fp.write(htmlsafe_dumps(obj, **kwargs))
235def jsonify(*args: t.Any, **kwargs: t.Any) -> "Response":
236 """Serialize data to JSON and wrap it in a :class:`~flask.Response`
237 with the :mimetype:`application/json` mimetype.
239 Uses :func:`dumps` to serialize the data, but ``args`` and
240 ``kwargs`` are treated as data rather than arguments to
241 :func:`json.dumps`.
243 1. Single argument: Treated as a single value.
244 2. Multiple arguments: Treated as a list of values.
245 ``jsonify(1, 2, 3)`` is the same as ``jsonify([1, 2, 3])``.
246 3. Keyword arguments: Treated as a dict of values.
247 ``jsonify(data=data, errors=errors)`` is the same as
248 ``jsonify({"data": data, "errors": errors})``.
249 4. Passing both arguments and keyword arguments is not allowed as
250 it's not clear what should happen.
252 .. code-block:: python
254 from flask import jsonify
256 @app.route("/users/me")
257 def get_current_user():
258 return jsonify(
259 username=g.user.username,
260 email=g.user.email,
261 id=g.user.id,
262 )
264 Will return a JSON response like this:
266 .. code-block:: javascript
268 {
269 "username": "admin",
270 "email": "admin@localhost",
271 "id": 42
272 }
274 The default output omits indents and spaces after separators. In
275 debug mode or if :data:`JSONIFY_PRETTYPRINT_REGULAR` is ``True``,
276 the output will be formatted to be easier to read.
278 .. versionchanged:: 2.0.2
279 :class:`decimal.Decimal` is supported by converting to a string.
281 .. versionchanged:: 0.11
282 Added support for serializing top-level arrays. This introduces
283 a security risk in ancient browsers. See :ref:`security-json`.
285 .. versionadded:: 0.2
286 """
287 indent = None
288 separators = (",", ":")
290 if current_app.config["JSONIFY_PRETTYPRINT_REGULAR"] or current_app.debug:
291 indent = 2
292 separators = (", ", ": ")
294 if args and kwargs:
295 raise TypeError("jsonify() behavior undefined when passed both args and kwargs")
296 elif len(args) == 1: # single args are passed directly to dumps()
297 data = args[0]
298 else:
299 data = args or kwargs
301 return current_app.response_class(
302 f"{dumps(data, indent=indent, separators=separators)}\n",
303 mimetype=current_app.config["JSONIFY_MIMETYPE"],
304 )