[O] json support more types
This commit is contained in:
+45
-29
@@ -4,9 +4,11 @@ import base64
|
|||||||
import dataclasses
|
import dataclasses
|
||||||
import datetime
|
import datetime
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import inspect
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import pickle
|
import pickle
|
||||||
|
from enum import EnumType, Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -37,36 +39,47 @@ def pickle_decode(by: bytes) -> Any:
|
|||||||
return pickle.load(bio)
|
return pickle.load(bio)
|
||||||
|
|
||||||
|
|
||||||
|
def infer(o: object) -> object | None:
|
||||||
|
# Support encoding dataclasses
|
||||||
|
# https://stackoverflow.com/a/51286749/7346633
|
||||||
|
if dataclasses.is_dataclass(o):
|
||||||
|
return dataclasses.asdict(o)
|
||||||
|
|
||||||
|
# Simple namespace
|
||||||
|
if isinstance(o, SimpleNamespace):
|
||||||
|
return o.__dict__
|
||||||
|
|
||||||
|
# Support encoding datetime
|
||||||
|
if isinstance(o, (datetime.datetime, datetime.date)):
|
||||||
|
return o.isoformat()
|
||||||
|
|
||||||
|
# Support for sets
|
||||||
|
# https://stackoverflow.com/a/8230505/7346633
|
||||||
|
if isinstance(o, set):
|
||||||
|
return list(o)
|
||||||
|
|
||||||
|
# Support for Path
|
||||||
|
if isinstance(o, Path):
|
||||||
|
return str(o)
|
||||||
|
|
||||||
|
# Support for byte arrays (encode as base64 string)
|
||||||
|
if isinstance(o, bytes):
|
||||||
|
return base64.b64encode(o).decode()
|
||||||
|
|
||||||
|
# Enums
|
||||||
|
if isinstance(o, Enum):
|
||||||
|
return o.name
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class EnhancedJSONEncoder(json.JSONEncoder):
|
class EnhancedJSONEncoder(json.JSONEncoder):
|
||||||
"""
|
"""
|
||||||
An improvement to the json.JSONEncoder class, which supports:
|
An improvement to the json.JSONEncoder class, which supports:
|
||||||
encoding for dataclasses, encoding for datetime, and sets
|
encoding for dataclasses, encoding for datetime, and sets
|
||||||
"""
|
"""
|
||||||
def default(self, o: object) -> object:
|
def default(self, o: object) -> object:
|
||||||
|
return infer(o) or super().default(o)
|
||||||
# Support encoding dataclasses
|
|
||||||
# https://stackoverflow.com/a/51286749/7346633
|
|
||||||
if dataclasses.is_dataclass(o):
|
|
||||||
return dataclasses.asdict(o)
|
|
||||||
|
|
||||||
# Simple namespace
|
|
||||||
if isinstance(o, SimpleNamespace):
|
|
||||||
return o.__dict__
|
|
||||||
|
|
||||||
# Support encoding datetime
|
|
||||||
if isinstance(o, (datetime.datetime, datetime.date)):
|
|
||||||
return o.isoformat()
|
|
||||||
|
|
||||||
# Support for sets
|
|
||||||
# https://stackoverflow.com/a/8230505/7346633
|
|
||||||
if isinstance(o, set):
|
|
||||||
return list(o)
|
|
||||||
|
|
||||||
# Support for Path
|
|
||||||
if isinstance(o, Path):
|
|
||||||
return str(o)
|
|
||||||
|
|
||||||
return super().default(o)
|
|
||||||
|
|
||||||
|
|
||||||
class ForceJSONEcoder(EnhancedJSONEncoder):
|
class ForceJSONEcoder(EnhancedJSONEncoder):
|
||||||
@@ -74,14 +87,17 @@ class ForceJSONEcoder(EnhancedJSONEncoder):
|
|||||||
A json encoder that can serialize almost everything (including custom classes, byte arrays)
|
A json encoder that can serialize almost everything (including custom classes, byte arrays)
|
||||||
"""
|
"""
|
||||||
def default(self, o: object) -> object:
|
def default(self, o: object) -> object:
|
||||||
|
infer_result = infer(o)
|
||||||
|
if infer_result:
|
||||||
|
return infer_result
|
||||||
|
|
||||||
# Support for byte arrays (encode as base64 string)
|
# Support EnumType
|
||||||
if isinstance(o, bytes):
|
if isinstance(o, EnumType):
|
||||||
return base64.b64encode(o).decode()
|
return {i.name: i.value for i in o}
|
||||||
|
|
||||||
# Support for custom classes (get dict values)
|
# Support for custom classes (get dict values)
|
||||||
if hasattr(o, '__dict__'):
|
if hasattr(o, '__dict__') and not inspect.isclass(o):
|
||||||
return vars(o)
|
return dict(vars(o))
|
||||||
|
|
||||||
return super().default(o)
|
return super().default(o)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user