-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathjsonifier.py
92 lines (73 loc) · 2.66 KB
/
jsonifier.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
"""
This module centralizes all functionality related to json encoding and decoding in Firetail.
"""
import datetime
import functools
import json
import typing as t
import uuid
from decimal import Decimal
def wrap_default(default_fn: t.Callable) -> t.Callable:
"""The Firetail defaults for JSON encoding. 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 float.
- :class:`uuid.UUID` is serialized to a string.
"""
@functools.wraps(default_fn)
def wrapped_default(self, o):
if isinstance(o, datetime.datetime):
if o.tzinfo:
# eg: '2015-09-25T23:14:42.588601+00:00'
return o.isoformat("T")
else:
# No timezone present - assume UTC.
# eg: '2015-09-25T23:14:42.588601Z'
return o.isoformat("T") + "Z"
if isinstance(o, datetime.date):
return o.isoformat()
if isinstance(o, Decimal):
return float(o)
if isinstance(o, uuid.UUID):
return str(o)
return default_fn(o)
return wrapped_default
class JSONEncoder(json.JSONEncoder):
"""The default Firetail JSON encoder. Handles extra types compared to the
built-in :class:`json.JSONEncoder`.
"""
@wrap_default
def default(self, o):
return super().default(o)
class Jsonifier:
"""
Central point to serialize and deserialize to/from JSon in Firetail.
"""
def __init__(self, json_=json, **kwargs):
"""
:param json_: json library to use. Must have loads() and dumps() method # NOQA
:param kwargs: default arguments to pass to json.dumps()
"""
self.json = json_
self.dumps_args = kwargs
self.dumps_args.setdefault("cls", JSONEncoder)
def dumps(self, data, **kwargs):
"""Central point where JSON serialization happens inside
Firetail.
"""
for k, v in self.dumps_args.items():
kwargs.setdefault(k, v)
return self.json.dumps(data, **kwargs) + "\n"
def loads(self, data):
"""Central point where JSON deserialization happens inside
Firetail.
"""
if isinstance(data, bytes):
data = data.decode()
try:
return self.json.loads(data)
except Exception:
if isinstance(data, str):
return data