Merge pull request #3195 from eruvanos/json_support_dataclass

Support dataclass in JSONEncoder (if available)
This commit is contained in:
David Lord 2019-05-18 21:44:21 -07:00 committed by GitHub
commit b0185a6205
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 5 deletions

View file

@ -38,6 +38,8 @@ Unreleased
dependency to >= 0.15. :issue:`3022` dependency to >= 0.15. :issue:`3022`
- Support ``static_url_path`` that ends with a forward slash. - Support ``static_url_path`` that ends with a forward slash.
:issue:`3134` :issue:`3134`
- :meth:`jsonify` supports :class:`dataclasses.dataclass` objects.
:pr:`3195`
.. _#2935: https://github.com/pallets/flask/issues/2935 .. _#2935: https://github.com/pallets/flask/issues/2935
.. _#2957: https://github.com/pallets/flask/issues/2957 .. _#2957: https://github.com/pallets/flask/issues/2957

View file

@ -20,6 +20,10 @@ from jinja2 import Markup
# depend anyways. # depend anyways.
from itsdangerous import json as _json from itsdangerous import json as _json
try:
import dataclasses
except ImportError:
dataclasses = None
# Figure out if simplejson escapes slashes. This behavior was changed # Figure out if simplejson escapes slashes. This behavior was changed
# from one version to another without reason. # from one version to another without reason.
@ -54,11 +58,15 @@ def _wrap_writer_for_text(fp, encoding):
class JSONEncoder(_json.JSONEncoder): class JSONEncoder(_json.JSONEncoder):
"""The default Flask JSON encoder. This one extends the default simplejson """The default Flask JSON encoder. This one extends the default
encoder by also supporting ``datetime`` objects, ``UUID`` as well as encoder by also supporting ``datetime``, ``UUID``, ``dataclasses``,
``Markup`` objects which are serialized as RFC 822 datetime strings (same and ``Markup`` objects.
as the HTTP date format). In order to support more data types override the
:meth:`default` method. ``datetime`` objects are serialized as RFC 822 datetime strings.
This is the same as the HTTP date format.
In order to support more data types, override the :meth:`default`
method.
""" """
def default(self, o): def default(self, o):
@ -84,6 +92,8 @@ class JSONEncoder(_json.JSONEncoder):
return http_date(o.timetuple()) return http_date(o.timetuple())
if isinstance(o, uuid.UUID): if isinstance(o, uuid.UUID):
return str(o) return str(o)
if dataclasses and dataclasses.is_dataclass(o):
return dataclasses.asdict(o)
if hasattr(o, "__html__"): if hasattr(o, "__html__"):
return text_type(o.__html__()) return text_type(o.__html__())
return _json.JSONEncoder.default(self, o) return _json.JSONEncoder.default(self, o)

View file

@ -10,6 +10,7 @@
""" """
import re import re
import sys
import time import time
import uuid import uuid
from datetime import datetime from datetime import datetime
@ -1289,6 +1290,14 @@ def test_jsonify_mimetype(app, req_ctx):
assert rv.mimetype == "application/vnd.api+json" assert rv.mimetype == "application/vnd.api+json"
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires Python >= 3.7")
def test_json_dump_dataclass(app, req_ctx):
from dataclasses import make_dataclass
Data = make_dataclass("Data", [("name", str)])
value = flask.json.dumps(Data("Flask"), app=app)
value = flask.json.loads(value, app=app)
assert value == {"name": "Flask"}
def test_jsonify_args_and_kwargs_check(app, req_ctx): def test_jsonify_args_and_kwargs_check(app, req_ctx):
with pytest.raises(TypeError) as e: with pytest.raises(TypeError) as e:
flask.jsonify("fake args", kwargs="fake") flask.jsonify("fake args", kwargs="fake")