__init__.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. from __future__ import annotations
  2. import json as _json
  3. import typing as t
  4. from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps
  5. from ..globals import current_app
  6. from .provider import _default
  7. if t.TYPE_CHECKING: # pragma: no cover
  8. from ..app import Flask
  9. from ..wrappers import Response
  10. class JSONEncoder(_json.JSONEncoder):
  11. """The default JSON encoder. Handles extra types compared to the
  12. built-in :class:`json.JSONEncoder`.
  13. - :class:`datetime.datetime` and :class:`datetime.date` are
  14. serialized to :rfc:`822` strings. This is the same as the HTTP
  15. date format.
  16. - :class:`decimal.Decimal` is serialized to a string.
  17. - :class:`uuid.UUID` is serialized to a string.
  18. - :class:`dataclasses.dataclass` is passed to
  19. :func:`dataclasses.asdict`.
  20. - :class:`~markupsafe.Markup` (or any object with a ``__html__``
  21. method) will call the ``__html__`` method to get a string.
  22. Assign a subclass of this to :attr:`flask.Flask.json_encoder` or
  23. :attr:`flask.Blueprint.json_encoder` to override the default.
  24. .. deprecated:: 2.2
  25. Will be removed in Flask 2.3. Use ``app.json`` instead.
  26. """
  27. def __init__(self, **kwargs) -> None:
  28. import warnings
  29. warnings.warn(
  30. "'JSONEncoder' is deprecated and will be removed in"
  31. " Flask 2.3. Use 'Flask.json' to provide an alternate"
  32. " JSON implementation instead.",
  33. DeprecationWarning,
  34. stacklevel=3,
  35. )
  36. super().__init__(**kwargs)
  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. return _default(o)
  44. class JSONDecoder(_json.JSONDecoder):
  45. """The default JSON decoder.
  46. This does not change any behavior from the built-in
  47. :class:`json.JSONDecoder`.
  48. Assign a subclass of this to :attr:`flask.Flask.json_decoder` or
  49. :attr:`flask.Blueprint.json_decoder` to override the default.
  50. .. deprecated:: 2.2
  51. Will be removed in Flask 2.3. Use ``app.json`` instead.
  52. """
  53. def __init__(self, **kwargs) -> None:
  54. import warnings
  55. warnings.warn(
  56. "'JSONDecoder' is deprecated and will be removed in"
  57. " Flask 2.3. Use 'Flask.json' to provide an alternate"
  58. " JSON implementation instead.",
  59. DeprecationWarning,
  60. stacklevel=3,
  61. )
  62. super().__init__(**kwargs)
  63. def dumps(obj: t.Any, *, app: Flask | None = None, **kwargs: t.Any) -> str:
  64. """Serialize data as JSON.
  65. If :data:`~flask.current_app` is available, it will use its
  66. :meth:`app.json.dumps() <flask.json.provider.JSONProvider.dumps>`
  67. method, otherwise it will use :func:`json.dumps`.
  68. :param obj: The data to serialize.
  69. :param kwargs: Arguments passed to the ``dumps`` implementation.
  70. .. versionchanged:: 2.2
  71. Calls ``current_app.json.dumps``, allowing an app to override
  72. the behavior.
  73. .. versionchanged:: 2.2
  74. The ``app`` parameter will be removed in Flask 2.3.
  75. .. versionchanged:: 2.0.2
  76. :class:`decimal.Decimal` is supported by converting to a string.
  77. .. versionchanged:: 2.0
  78. ``encoding`` will be removed in Flask 2.1.
  79. .. versionchanged:: 1.0.3
  80. ``app`` can be passed directly, rather than requiring an app
  81. context for configuration.
  82. """
  83. if app is not None:
  84. import warnings
  85. warnings.warn(
  86. "The 'app' parameter is deprecated and will be removed in"
  87. " Flask 2.3. Call 'app.json.dumps' directly instead.",
  88. DeprecationWarning,
  89. stacklevel=2,
  90. )
  91. else:
  92. app = current_app
  93. if app:
  94. return app.json.dumps(obj, **kwargs)
  95. kwargs.setdefault("default", _default)
  96. return _json.dumps(obj, **kwargs)
  97. def dump(
  98. obj: t.Any, fp: t.IO[str], *, app: Flask | None = None, **kwargs: t.Any
  99. ) -> None:
  100. """Serialize data as JSON and write to a file.
  101. If :data:`~flask.current_app` is available, it will use its
  102. :meth:`app.json.dump() <flask.json.provider.JSONProvider.dump>`
  103. method, otherwise it will use :func:`json.dump`.
  104. :param obj: The data to serialize.
  105. :param fp: A file opened for writing text. Should use the UTF-8
  106. encoding to be valid JSON.
  107. :param kwargs: Arguments passed to the ``dump`` implementation.
  108. .. versionchanged:: 2.2
  109. Calls ``current_app.json.dump``, allowing an app to override
  110. the behavior.
  111. .. versionchanged:: 2.2
  112. The ``app`` parameter will be removed in Flask 2.3.
  113. .. versionchanged:: 2.0
  114. Writing to a binary file, and the ``encoding`` argument, will be
  115. removed in Flask 2.1.
  116. """
  117. if app is not None:
  118. import warnings
  119. warnings.warn(
  120. "The 'app' parameter is deprecated and will be removed in"
  121. " Flask 2.3. Call 'app.json.dump' directly instead.",
  122. DeprecationWarning,
  123. stacklevel=2,
  124. )
  125. else:
  126. app = current_app
  127. if app:
  128. app.json.dump(obj, fp, **kwargs)
  129. else:
  130. kwargs.setdefault("default", _default)
  131. _json.dump(obj, fp, **kwargs)
  132. def loads(s: str | bytes, *, app: Flask | None = None, **kwargs: t.Any) -> t.Any:
  133. """Deserialize data as JSON.
  134. If :data:`~flask.current_app` is available, it will use its
  135. :meth:`app.json.loads() <flask.json.provider.JSONProvider.loads>`
  136. method, otherwise it will use :func:`json.loads`.
  137. :param s: Text or UTF-8 bytes.
  138. :param kwargs: Arguments passed to the ``loads`` implementation.
  139. .. versionchanged:: 2.2
  140. Calls ``current_app.json.loads``, allowing an app to override
  141. the behavior.
  142. .. versionchanged:: 2.2
  143. The ``app`` parameter will be removed in Flask 2.3.
  144. .. versionchanged:: 2.0
  145. ``encoding`` will be removed in Flask 2.1. The data must be a
  146. string or UTF-8 bytes.
  147. .. versionchanged:: 1.0.3
  148. ``app`` can be passed directly, rather than requiring an app
  149. context for configuration.
  150. """
  151. if app is not None:
  152. import warnings
  153. warnings.warn(
  154. "The 'app' parameter is deprecated and will be removed in"
  155. " Flask 2.3. Call 'app.json.loads' directly instead.",
  156. DeprecationWarning,
  157. stacklevel=2,
  158. )
  159. else:
  160. app = current_app
  161. if app:
  162. return app.json.loads(s, **kwargs)
  163. return _json.loads(s, **kwargs)
  164. def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **kwargs: t.Any) -> t.Any:
  165. """Deserialize data as JSON read from a file.
  166. If :data:`~flask.current_app` is available, it will use its
  167. :meth:`app.json.load() <flask.json.provider.JSONProvider.load>`
  168. method, otherwise it will use :func:`json.load`.
  169. :param fp: A file opened for reading text or UTF-8 bytes.
  170. :param kwargs: Arguments passed to the ``load`` implementation.
  171. .. versionchanged:: 2.2
  172. Calls ``current_app.json.load``, allowing an app to override
  173. the behavior.
  174. .. versionchanged:: 2.2
  175. The ``app`` parameter will be removed in Flask 2.3.
  176. .. versionchanged:: 2.0
  177. ``encoding`` will be removed in Flask 2.1. The file must be text
  178. mode, or binary mode with UTF-8 bytes.
  179. """
  180. if app is not None:
  181. import warnings
  182. warnings.warn(
  183. "The 'app' parameter is deprecated and will be removed in"
  184. " Flask 2.3. Call 'app.json.load' directly instead.",
  185. DeprecationWarning,
  186. stacklevel=2,
  187. )
  188. else:
  189. app = current_app
  190. if app:
  191. return app.json.load(fp, **kwargs)
  192. return _json.load(fp, **kwargs)
  193. def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str:
  194. """Serialize an object to a string of JSON with :func:`dumps`, then
  195. replace HTML-unsafe characters with Unicode escapes and mark the
  196. result safe with :class:`~markupsafe.Markup`.
  197. This is available in templates as the ``|tojson`` filter.
  198. The returned string is safe to render in HTML documents and
  199. ``<script>`` tags. The exception is in HTML attributes that are
  200. double quoted; either use single quotes or the ``|forceescape``
  201. filter.
  202. .. deprecated:: 2.2
  203. Will be removed in Flask 2.3. This is built-in to Jinja now.
  204. .. versionchanged:: 2.0
  205. Uses :func:`jinja2.utils.htmlsafe_json_dumps`. The returned
  206. value is marked safe by wrapping in :class:`~markupsafe.Markup`.
  207. .. versionchanged:: 0.10
  208. Single quotes are escaped, making this safe to use in HTML,
  209. ``<script>`` tags, and single-quoted attributes without further
  210. escaping.
  211. """
  212. import warnings
  213. warnings.warn(
  214. "'htmlsafe_dumps' is deprecated and will be removed in Flask"
  215. " 2.3. Use 'jinja2.utils.htmlsafe_json_dumps' instead.",
  216. DeprecationWarning,
  217. stacklevel=2,
  218. )
  219. return _jinja_htmlsafe_dumps(obj, dumps=dumps, **kwargs)
  220. def htmlsafe_dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None:
  221. """Serialize an object to JSON written to a file object, replacing
  222. HTML-unsafe characters with Unicode escapes. See
  223. :func:`htmlsafe_dumps` and :func:`dumps`.
  224. .. deprecated:: 2.2
  225. Will be removed in Flask 2.3.
  226. """
  227. import warnings
  228. warnings.warn(
  229. "'htmlsafe_dump' is deprecated and will be removed in Flask"
  230. " 2.3. Use 'jinja2.utils.htmlsafe_json_dumps' instead.",
  231. DeprecationWarning,
  232. stacklevel=2,
  233. )
  234. fp.write(htmlsafe_dumps(obj, **kwargs))
  235. def jsonify(*args: t.Any, **kwargs: t.Any) -> Response:
  236. """Serialize the given arguments as JSON, and return a
  237. :class:`~flask.Response` object with the ``application/json``
  238. mimetype. A dict or list returned from a view will be converted to a
  239. JSON response automatically without needing to call this.
  240. This requires an active request or application context, and calls
  241. :meth:`app.json.response() <flask.json.provider.JSONProvider.response>`.
  242. In debug mode, the output is formatted with indentation to make it
  243. easier to read. This may also be controlled by the provider.
  244. Either positional or keyword arguments can be given, not both.
  245. If no arguments are given, ``None`` is serialized.
  246. :param args: A single value to serialize, or multiple values to
  247. treat as a list to serialize.
  248. :param kwargs: Treat as a dict to serialize.
  249. .. versionchanged:: 2.2
  250. Calls ``current_app.json.response``, allowing an app to override
  251. the behavior.
  252. .. versionchanged:: 2.0.2
  253. :class:`decimal.Decimal` is supported by converting to a string.
  254. .. versionchanged:: 0.11
  255. Added support for serializing top-level arrays. This was a
  256. security risk in ancient browsers. See :ref:`security-json`.
  257. .. versionadded:: 0.2
  258. """
  259. return current_app.json.response(*args, **kwargs)