-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserializable.py
77 lines (60 loc) · 1.99 KB
/
serializable.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
import json
from abc import ABC
from abc import abstractmethod
from datetime import datetime
from datetime import timedelta
from enum import Enum
from pathlib import Path
from typing import Any
from typing import Dict
from typing import overload
from typing import Protocol
from typing import Type
from typing import TypeVar
from typing import Union
from utils import Timedelta
T = TypeVar('T', bound='_JSONSerializable', covariant=True)
class _JSONSerializable(Protocol[T]):
def to_json(self) -> Dict[str, Any]: ...
@classmethod
def from_json(cls: Type[T], json: Dict[str, Any]) -> T: ...
@overload
def _jsonify(value: Union[str, Path, timedelta, Timedelta, datetime]) -> str: ...
@overload
def _jsonify(value: None) -> None: ...
@overload
def _jsonify(value: _JSONSerializable) -> Dict[str, Any]: ...
def _jsonify(value):
if isinstance(value, Path):
return str(value)
if isinstance(value, list):
return [_jsonify(val) for val in value]
if isinstance(value, datetime):
return value.isoformat()
if isinstance(value, JSONSerializable):
return value.to_json()
if isinstance(value, (timedelta, Timedelta)):
return '{}:{}:{}'.format(value.days, value.seconds, value.microseconds)
if isinstance(value, Enum):
return value.value
return value
class JSONSerializable(ABC, _JSONSerializable):
def to_json(self) -> Dict[str, Any]:
return {
key: _jsonify(getattr(self, key))
for key in self.__annotations__
}
@classmethod
@abstractmethod
def from_json(cls: Type[T], json: Dict[str, Any]) -> T:
pass
@classmethod
def load(cls: Type[T], file_path: Path) -> T:
try:
with open(file_path) as f:
return cls.from_json(json.load(f))
except FileNotFoundError:
return cls()
def dump(self, path: Path) -> None:
with open(path, 'w') as f:
f.write(json.dumps(self.to_json(), indent=4, sort_keys=True))