From 4f18acae751806ac7ceb306a06517f382ce1b6df Mon Sep 17 00:00:00 2001 From: "J. Rast" Date: Sun, 7 Aug 2022 15:56:37 +0200 Subject: [PATCH] Use the old JSONEncoder from flask as a default Created a copy of the deprecated JSONEncoder used by flask and use this as a default for PyJWT. This might break for some installations which further extended the flask provided JSONEncoder. To get this working again the extension must be adjusted such that a custom Encoder can be configured. --- flask_jwt_extended/config.py | 31 +++++++++++++++++++++++++++++-- tests/test_config.py | 10 ---------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/flask_jwt_extended/config.py b/flask_jwt_extended/config.py index 05322d8d..f0339b15 100644 --- a/flask_jwt_extended/config.py +++ b/flask_jwt_extended/config.py @@ -1,6 +1,8 @@ +import json from datetime import datetime from datetime import timedelta from datetime import timezone +from typing import Any from typing import Iterable from typing import List from typing import Optional @@ -9,12 +11,37 @@ from typing import Union from flask import current_app -from flask.json import JSONEncoder +from flask.json.provider import _default from jwt.algorithms import requires_cryptography from flask_jwt_extended.typing import ExpiresDelta +class JSONEncoder(json.JSONEncoder): + """The default JSON encoder. Handles extra types compared to the + built-in :class:`json.JSONEncoder`. + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :class:`decimal.Decimal` is serialized to a string. + - :class:`uuid.UUID` is serialized to a string. + - :class:`dataclasses.dataclass` is passed to + :func:`dataclasses.asdict`. + - :class:`~markupsafe.Markup` (or any object with a ``__html__`` + method) will call the ``__html__`` method to get a string. + + """ + + def default(self, o: Any) -> Any: + """Convert ``o`` to a JSON serializable type. See + :meth:`json.JSONEncoder.default`. Python does not support + overriding how basic types like ``str`` or ``list`` are + serialized, they are handled before this method. + """ + return _default(o) + + class _Config(object): """ Helper object for accessing and verifying options in this extension. This @@ -284,7 +311,7 @@ def error_msg_key(self) -> str: @property def json_encoder(self) -> Type[JSONEncoder]: - return current_app.json_encoder + return JSONEncoder @property def decode_audience(self) -> Union[str, Iterable[str]]: diff --git a/tests/test_config.py b/tests/test_config.py index 343d1e66..a5515ab8 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -3,7 +3,6 @@ import pytest from dateutil.relativedelta import relativedelta from flask import Flask -from flask.json import JSONEncoder from flask_jwt_extended import JWTManager from flask_jwt_extended.config import config @@ -65,8 +64,6 @@ def test_default_configs(app): assert config.identity_claim_key == "sub" - assert config.json_encoder is app.json_encoder - assert config.error_msg_key == "msg" @@ -112,11 +109,6 @@ def test_override_configs(app, delta_func): app.config["JWT_ERROR_MESSAGE_KEY"] = "message" - class CustomJSONEncoder(JSONEncoder): - pass - - app.json_encoder = CustomJSONEncoder - with app.test_request_context(): assert config.token_location == ["cookies", "query_string", "json"] assert config.jwt_in_query_string is True @@ -162,8 +154,6 @@ class CustomJSONEncoder(JSONEncoder): assert config.identity_claim_key == "foo" - assert config.json_encoder is CustomJSONEncoder - assert config.error_msg_key == "message"