-
Notifications
You must be signed in to change notification settings - Fork 5
/
json_util.py
103 lines (94 loc) · 3.27 KB
/
json_util.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
# Copyright 2009-2010 10gen, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This is a copy of bson.json_util, but justs converts what is in the _id field
to and from an ObjectId instance. Won't work with embedded object ids.
"""
import calendar
import datetime
import re
try:
import uuid
_use_uuid = True
except ImportError:
_use_uuid = False
from bson.dbref import DBRef
from bson.max_key import MaxKey
from bson.min_key import MinKey
from bson.objectid import ObjectId
from bson.timestamp import Timestamp
from bson.tz_util import utc
# TODO support Binary and Code
# Binary and Code are tricky because they subclass str so json thinks it can
# handle them. Not sure what the proper way to get around this is...
#
# One option is to just add some other method that users need to call _before_
# calling json.dumps or json.loads. That is pretty terrible though...
# TODO share this with bson.py?
_RE_TYPE = type(re.compile("foo"))
def object_hook(dct):
print 'oh', dct
if '_id' in dct:
dct['_id'] = ObjectId(str(dct["_id"]))
return dct
if "$oid" in dct:
return ObjectId(str(dct["$oid"]))
if "$ref" in dct:
return DBRef(dct["$ref"], dct["$id"], dct.get("$db", None))
if "$date" in dct:
return datetime.datetime.fromtimestamp(float(dct["$date"]) / 1000.0,
utc)
if "$regex" in dct:
flags = 0
if "i" in dct["$options"]:
flags |= re.IGNORECASE
if "m" in dct["$options"]:
flags |= re.MULTILINE
return re.compile(dct["$regex"], flags)
if "$minKey" in dct:
return MinKey()
if "$maxKey" in dct:
return MaxKey()
if _use_uuid and "$uuid" in dct:
return uuid.UUID(dct["$uuid"])
return dct
def default(obj):
if isinstance(obj, ObjectId):
return str(obj)
if isinstance(obj, DBRef):
return obj.as_doc()
if isinstance(obj, datetime.datetime):
# TODO share this code w/ bson.py?
if obj.utcoffset() is not None:
obj = obj - obj.utcoffset()
millis = int(calendar.timegm(obj.timetuple()) * 1000 +
obj.microsecond / 1000)
return {"$date": millis}
if isinstance(obj, _RE_TYPE):
flags = ""
if obj.flags & re.IGNORECASE:
flags += "i"
if obj.flags & re.MULTILINE:
flags += "m"
return {"$regex": obj.pattern,
"$options": flags}
if isinstance(obj, MinKey):
return {"$minKey": 1}
if isinstance(obj, MaxKey):
return {"$maxKey": 1}
if isinstance(obj, Timestamp):
return {"t": obj.time, "i": obj.inc}
if _use_uuid and isinstance(obj, uuid.UUID):
return {"$uuid": obj.hex}
raise TypeError("%r is not JSON serializable" % obj)