Enhancing JSON Serialization In Python With Typing

The Problem

from datetime import datetime
from decimal import Decimal

dct = {
'some_text': 'Hello, World!',
'some_date': datetime.fromisoformat('2020-01-29T12:56:13'),
'some_int': 42,
'some_float': 3.14,
'some_decimal': Decimal("2.414"),
'some_list': [
{
'other_text': 'Hello, World!',
'other_date': datetime.fromisoformat('2020-01-29T12:56:13'),
'other_decimal': Decimal("2.414")
},
{
'other_text': 'Hello, World!',
'other_date': datetime.fromisoformat('2020-01-29T12:56:13'),
'other_decimal': Decimal('2.414')
}
]
}
import json

try:
text = json.dumps(dct)
except Exception as error:
print(error)

Object of type datetime is not JSON serializable
class MyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Decimal):
return float(obj)
text = json.dumps(dct, cls=MyEncoder, indent=4)
print(text)
{
"some_text": "Hello, World!",
"some_date": "2020-01-29T12:56:13",
"some_int": 42,
"some_float": 3.14,
"some_decimal": 2.414,
"some_list": [
{
"other_text": "Hello, World!",
"other_date": "2020-01-29T12:56:13",
"other_decimal": 2.414
},
{
"other_text": "Hello, World!",
"other_date": "2020-01-29T12:56:13",
"other_decimal": 2.414
}
]
}
obj1 = json.loads(text)
print(obj1)
{
'some_text': 'Hello, World!',
'some_date': '2020-01-29T12:56:13',
'some_int': 42,
'some_float': 3.14,
'some_decimal': 2.414,
'some_list': [
{
'other_text': 'Hello, World!',
'other_date': '2020-01-29T12:56:13',
'other_decimal': 2.414
},
{
'other_text': 'Hello, World!',
'other_date': '2020-01-29T12:56:13',
'other_decimal': 2.414
}
]
}
print(dct == obj1)
False
def object_hook(dct):
for key, value in dct.items():
try:
dct[key] = datetime.fromisoformat(value)
except:
pass
return dct
obj2 = json.loads(text, object_hook=object_hook)
print(obj2)
{
'some_text': 'Hello, World!',
'some_date': datetime.datetime(2020, 1, 29, 12, 56, 13),
'some_int': 42,
'some_float': 3.14,
'some_decimal': 2.414,
'some_list': [
{
'other_text': 'Hello, World!',
'other_date': datetime.datetime(2020, 1, 29, 12, 56, 13),
'other_decimal': 2.414
},
{
'other_text': 'Hello, World!',
'other_date': datetime.datetime(2020, 1, 29, 12, 56, 13),
'other_decimal': 2.414
}
]
}
print(dct == obj2)
False

Type Annotations

from typing import List
try:
from typing import TypedDict
except:
from typing_extensions import TypedDict

class InnerDict(TypedDict):
other_text: str
other_date: datetime
other_decimal: Decimal

class OuterDict(TypedDict):
some_text: str
some_date: datetime
some_int: int
some_float: float
some_decimal: Decimal
some_list: List[InnerDict]
from jetblack_serialization.config import SerializerConfig
from jetblack_serialization.json import deserialize, serialize
from stringcase import camelcase, snakecase

config = SerializerConfig(camelcase, snakecase, pretty_print=True)

text = serialize(dct, OuterDict, config)
print(text)
{
"someText": "Hello, World!",
"someDate": "2020-01-29T12:56:13.00Z",
"someInt": 42,
"someFloat": 3.14,
"someDecimal": 2.414,
"someList": [
{
"otherText": "Hello, World!",
"otherDate": "2020-01-29T12:56:13.00Z",
"otherDecimal": 2.414
},
{
"otherText": "Hello, World!",
"otherDate": "2020-01-29T12:56:13.00Z",
"otherDecimal": 2.414
}
]
}
obj = deserialize(text, OuterDict, config)
print(obj)
{
'some_text': 'Hello, World!',
'some_date': datetime.datetime(2020, 1, 29, 12, 56, 13),
'some_int': 42,
'some_float': 3.14,
'some_decimal': Decimal('2.414'),
'some_list': [
{
'other_text': 'Hello, World!',
'other_date': datetime.datetime(2020, 1, 29, 12, 56, 13),
'other_decimal': Decimal('2.414')
},
{
'other_text': 'Hello, World!',
'other_date': datetime.datetime(2020, 1, 29, 12, 56, 13),
'other_decimal': Decimal('2.414')
}
]
}
print(dct == obj)
True
from typing_extensions import Annotated
from jetblack_serialization.xml import serialize as serialize_xml, XMLEntity
from stringcase import pascalcase

xml_config = SerializerConfig(pascalcase, snakecase, pretty_print=True)

text = serialize_xml(dct, Annotated[OuterDict, XMLEntity('Dict')], xml_config)
print(text)
<Dict>
<SomeText>Hello, World!</SomeText>
<SomeDate>2020-01-29T12:56:13.00Z</SomeDate>
<SomeInt>42</SomeInt>
<SomeFloat>3.14</SomeFloat>
<SomeDecimal>2.414</SomeDecimal>
<SomeList>
<OtherText>Hello, World!</OtherText>
<OtherDate>2020-01-29T12:56:13.00Z</OtherDate>
<OtherDecimal>2.414</OtherDecimal>
</SomeList>
<SomeList>
<OtherText>Hello, World!</OtherText>
<OtherDate>2020-01-29T12:56:13.00Z</OtherDate>
<OtherDecimal>2.414</OtherDecimal>
</SomeList>
</Dict>

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store