json.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. from __future__ import absolute_import
  2. import datetime
  3. import uuid
  4. from .._compat import text_type
  5. from ..exceptions import BadRequest
  6. from ..utils import detect_utf_encoding
  7. try:
  8. import simplejson as _json
  9. except ImportError:
  10. import json as _json
  11. class _JSONModule(object):
  12. @staticmethod
  13. def _default(o):
  14. if isinstance(o, datetime.date):
  15. return o.isoformat()
  16. if isinstance(o, uuid.UUID):
  17. return str(o)
  18. if hasattr(o, "__html__"):
  19. return text_type(o.__html__())
  20. raise TypeError()
  21. @classmethod
  22. def dumps(cls, obj, **kw):
  23. kw.setdefault("separators", (",", ":"))
  24. kw.setdefault("default", cls._default)
  25. kw.setdefault("sort_keys", True)
  26. return _json.dumps(obj, **kw)
  27. @staticmethod
  28. def loads(s, **kw):
  29. if isinstance(s, bytes):
  30. # Needed for Python < 3.6
  31. encoding = detect_utf_encoding(s)
  32. s = s.decode(encoding)
  33. return _json.loads(s, **kw)
  34. class JSONMixin(object):
  35. """Mixin to parse :attr:`data` as JSON. Can be mixed in for both
  36. :class:`~werkzeug.wrappers.Request` and
  37. :class:`~werkzeug.wrappers.Response` classes.
  38. If `simplejson`_ is installed it is preferred over Python's built-in
  39. :mod:`json` module.
  40. .. _simplejson: https://simplejson.readthedocs.io/en/latest/
  41. """
  42. #: A module or other object that has ``dumps`` and ``loads``
  43. #: functions that match the API of the built-in :mod:`json` module.
  44. json_module = _JSONModule
  45. @property
  46. def json(self):
  47. """The parsed JSON data if :attr:`mimetype` indicates JSON
  48. (:mimetype:`application/json`, see :meth:`is_json`).
  49. Calls :meth:`get_json` with default arguments.
  50. """
  51. return self.get_json()
  52. @property
  53. def is_json(self):
  54. """Check if the mimetype indicates JSON data, either
  55. :mimetype:`application/json` or :mimetype:`application/*+json`.
  56. """
  57. mt = self.mimetype
  58. return (
  59. mt == "application/json"
  60. or mt.startswith("application/")
  61. and mt.endswith("+json")
  62. )
  63. def _get_data_for_json(self, cache):
  64. try:
  65. return self.get_data(cache=cache)
  66. except TypeError:
  67. # Response doesn't have cache param.
  68. return self.get_data()
  69. # Cached values for ``(silent=False, silent=True)``. Initialized
  70. # with sentinel values.
  71. _cached_json = (Ellipsis, Ellipsis)
  72. def get_json(self, force=False, silent=False, cache=True):
  73. """Parse :attr:`data` as JSON.
  74. If the mimetype does not indicate JSON
  75. (:mimetype:`application/json`, see :meth:`is_json`), this
  76. returns ``None``.
  77. If parsing fails, :meth:`on_json_loading_failed` is called and
  78. its return value is used as the return value.
  79. :param force: Ignore the mimetype and always try to parse JSON.
  80. :param silent: Silence parsing errors and return ``None``
  81. instead.
  82. :param cache: Store the parsed JSON to return for subsequent
  83. calls.
  84. """
  85. if cache and self._cached_json[silent] is not Ellipsis:
  86. return self._cached_json[silent]
  87. if not (force or self.is_json):
  88. return None
  89. data = self._get_data_for_json(cache=cache)
  90. try:
  91. rv = self.json_module.loads(data)
  92. except ValueError as e:
  93. if silent:
  94. rv = None
  95. if cache:
  96. normal_rv, _ = self._cached_json
  97. self._cached_json = (normal_rv, rv)
  98. else:
  99. rv = self.on_json_loading_failed(e)
  100. if cache:
  101. _, silent_rv = self._cached_json
  102. self._cached_json = (rv, silent_rv)
  103. else:
  104. if cache:
  105. self._cached_json = (rv, rv)
  106. return rv
  107. def on_json_loading_failed(self, e):
  108. """Called if :meth:`get_json` parsing fails and isn't silenced.
  109. If this method returns a value, it is used as the return value
  110. for :meth:`get_json`. The default implementation raises
  111. :exc:`~werkzeug.exceptions.BadRequest`.
  112. """
  113. raise BadRequest("Failed to decode JSON object: {0}".format(e))