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`
- Support ``static_url_path`` that ends with a forward slash.
:issue:`3134`
- :meth:`jsonify` supports :class:`dataclasses.dataclass` objects.
:pr:`3195`
.. _#2935: https://github.com/pallets/flask/issues/2935
.. _#2957: https://github.com/pallets/flask/issues/2957

View File

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

View File

@ -10,6 +10,7 @@
"""
import re
import sys
import time
import uuid
from datetime import datetime
@ -1289,6 +1290,14 @@ def test_jsonify_mimetype(app, req_ctx):
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):
with pytest.raises(TypeError) as e:
flask.jsonify("fake args", kwargs="fake")