-
Notifications
You must be signed in to change notification settings - Fork 255
/
Copy pathjson.py
117 lines (91 loc) · 3.64 KB
/
json.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
"""Flask application JSON extension functions."""
from functools import lru_cache
from bson import DBRef, ObjectId, json_util
from mongoengine.base import BaseDocument
from mongoengine.queryset import QuerySet
from pymongo.command_cursor import CommandCursor
@lru_cache(maxsize=1)
def use_json_provider() -> bool:
"""Split Flask before 2.2.0 and after, to use/not use JSON provider approach."""
from flask import __version__
version = list(__version__.split("."))
return int(version[0]) > 2 or (int(version[0]) == 2 and int(version[1]) > 1)
# noinspection PyProtectedMember
def _convert_mongo_objects(obj):
"""Convert objects, related to Mongo database to JSON."""
converted = None
if isinstance(obj, BaseDocument):
converted = json_util._json_convert(obj.to_mongo())
elif isinstance(obj, QuerySet):
converted = json_util._json_convert(obj.as_pymongo())
elif isinstance(obj, CommandCursor):
converted = json_util._json_convert(obj)
elif isinstance(obj, DBRef):
converted = obj.id
elif isinstance(obj, ObjectId):
converted = obj.__str__()
return converted
def _make_encoder(superclass):
"""Extend Flask JSON Encoder 'default' method with support of Mongo objects."""
import warnings
warnings.warn(
(
"JSONEncoder/JSONDecoder are deprecated in Flask 2.2 and will be removed "
"in Flask 2.3."
),
DeprecationWarning,
stacklevel=2,
)
class MongoEngineJSONEncoder(superclass):
"""
A JSONEncoder which provides serialization of MongoEngine
documents and queryset objects.
"""
def default(self, obj):
"""Extend JSONEncoder default method, with Mongo objects."""
if isinstance(
obj,
(BaseDocument, QuerySet, CommandCursor, DBRef, ObjectId),
):
return _convert_mongo_objects(obj)
return super().default(obj)
return MongoEngineJSONEncoder
def _update_json_provider(superclass):
"""Extend Flask Provider 'default' static method with support of Mongo objects."""
class MongoEngineJSONProvider(superclass):
"""A JSON Provider update for Flask 2.2.0+"""
@staticmethod
def default(obj):
"""Extend JSONProvider default static method, with Mongo objects."""
if isinstance(
obj,
(BaseDocument, QuerySet, CommandCursor, DBRef, ObjectId),
):
return _convert_mongo_objects(obj)
return super().default(obj)
return MongoEngineJSONProvider
# Compatibility code for Flask 2.2.0+ support
MongoEngineJSONEncoder = None
MongoEngineJSONProvider = None
if use_json_provider():
from flask.json.provider import DefaultJSONProvider
MongoEngineJSONProvider = _update_json_provider(DefaultJSONProvider)
else:
from flask.json import JSONEncoder
MongoEngineJSONEncoder = _make_encoder(JSONEncoder)
# End of compatibility code
def override_json_encoder(app):
"""
A function to dynamically create a new MongoEngineJSONEncoder class
based upon a custom base class.
This function allows us to combine MongoEngine serialization with
any changes to Flask's JSONEncoder which a user may have made
prior to calling init_app.
NOTE: This does not cover situations where users override
an instance's json_encoder after calling init_app.
"""
if use_json_provider():
app.json_provider_class = _update_json_provider(app.json_provider_class)
app.json = app.json_provider_class(app)
else:
app.json_encoder = _make_encoder(app.json_encoder)