This repository was archived by the owner on Oct 23, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 651
Expand file tree
/
Copy pathjson.py
More file actions
130 lines (90 loc) · 3.06 KB
/
json.py
File metadata and controls
130 lines (90 loc) · 3.06 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
"""
raven.utils.json
~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2010-2012 by the Sentry Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from __future__ import absolute_import
import codecs
import collections
import datetime
import uuid
import json
from .basic import is_namedtuple
from .compat import PY2
try:
JSONDecodeError = json.JSONDecodeError
except AttributeError:
JSONDecodeError = ValueError
class BetterJSONEncoder(json.JSONEncoder):
ENCODER_BY_TYPE = {
uuid.UUID: lambda o: o.hex,
datetime.datetime: lambda o: o.strftime('%Y-%m-%dT%H:%M:%SZ'),
set: list,
frozenset: list,
bytes: lambda o: o.decode('utf-8', errors='replace'),
collections.namedtuple: lambda o: o._asdict(),
}
def default(self, obj):
obj_type = type(obj)
if obj_type not in self.ENCODER_BY_TYPE and is_namedtuple(obj):
obj_type = collections.namedtuple
try:
encoder = self.ENCODER_BY_TYPE[obj_type]
except KeyError:
try:
return super(BetterJSONEncoder, self).default(obj)
except Exception:
try:
return repr(obj)
except Exception:
return object.__repr__(obj)
return encoder(obj)
def better_decoder(data):
return data
def dumps(value, **kwargs):
kwargs['skipkeys'] = True
try:
return json.dumps(value, cls=BetterJSONEncoder, **kwargs)
except Exception:
if PY2:
# 'encoding' is only available in Py2
kwargs['encoding'] = 'safe-utf-8'
return json.dumps(value, cls=BetterJSONEncoder, **kwargs)
else:
raise
def loads(value, **kwargs):
return json.loads(value, object_hook=better_decoder)
_utf8_encoder = codecs.getencoder('utf-8')
def safe_encode(input, errors='backslashreplace'):
return _utf8_encoder(input, errors)
_utf8_decoder = codecs.getdecoder('utf-8')
def safe_decode(input, errors='replace'):
return _utf8_decoder(input, errors)
class Codec(codecs.Codec):
def encode(self, input, errors='backslashreplace'):
return safe_encode(input, errors)
def decode(self, input, errors='replace'):
return safe_decode(input, errors)
class IncrementalEncoder(codecs.IncrementalEncoder):
def encode(self, input, final=False):
return safe_encode(input, self.errors)[0]
class IncrementalDecoder(codecs.IncrementalDecoder):
def decode(self, input, final=False):
return safe_decode(input, self.errors)[0]
class StreamWriter(Codec, codecs.StreamWriter):
pass
class StreamReader(Codec, codecs.StreamReader):
pass
def getregentry(name):
if name == 'safe-utf-8':
return codecs.CodecInfo(
name=name,
encode=safe_encode,
decode=safe_decode,
incrementalencoder=IncrementalEncoder,
incrementaldecoder=IncrementalDecoder,
streamreader=StreamReader,
streamwriter=StreamWriter,
)
codecs.register(getregentry)