jetblack-serialization
Serialization of built in types for JSON, YAML and XML in Python using type annotations (read the docs).
Installation
This is a Python 3.12+ package.
The package can be installed with pip.
pip install jetblack-serialization
By default, the dependencies for YAML and XML are not installed.
To install the dependencies for XML
(lxml).
pip install jetblack-serialization[xml]
To install the dependencies for YAML (PyYAML).
pip install jetblack-serialization[yaml]
To install the dependencies for all.
pip install jetblack-serialization[xml,yaml]
Overview
The package adds support for type annotations when serializing or deserializing JSON, YAML or XML.
JSON
Given a typed dictionary:
from datetime import datetime
from typing import Optional, TypedDict, Union
class Book(TypedDict, total=False):
book_id: int
title: str
author: str
publication_date: datetime
keywords: list[str]
phrases: list[str]
age: Optional[Union[datetime, int]]
pages: Optional[int]
Serializing JSON
This could be serialized to JSON as:
from stringcase import camelcase
from jetblack_serialization.json import serialize, SerializerConfig
obj: Book = {
'author': 'Chairman Mao',
'book_id': 42,
'title': 'Little Red Book',
'publication_date': datetime(1973, 1, 1, 21, 52, 13),
'keywords': ['Revolution', 'Communism'],
'phrases': [
'Revolutionary wars are inevitable in class society',
'War is the continuation of politics'
],
'age': 24,
}
text = serialize(
obj,
Book,
SerializerConfig(key_serializer=camelcase, pretty_print=True)
)
print(text)
giving:
{
"bookId": 42,
"title": "Little Red Book",
"author": "Chairman Mao",
"publicationDate": "1973-01-01T21:52:13.00Z",
"keywords": ["Revolution", "Communism"],
"phrases": ["Revolutionary wars are inevitable in class society", "War is the continuation of politics"],
"age": 24,
"pages": null
}
Note the fields have been camel cased, and the publication date has been turned into an ISO 8601 date.
Deserializing JSON
We can deserialize the data as follows:
from stringcase import snakecase
from jetblack_serialization.json import deserialize, SerializerConfig
dct = deserialize(
text,
Annotated[Book, JSONValue()],
SerializerConfig(key_deserializer=snakecase)
)
YAML
YAML is a superset of JSON, so for serialization things are very similar.
Given a typed dictionary:
from datetime import datetime
from typing import Optional, TypedDict, Union
class Book(TypedDict, total=False):
book_id: int
title: str
author: str
publication_date: datetime
keywords: list[str]
phrases: list[str]
age: Optional[Union[datetime, int]]
pages: Optional[int]
Serializing YAML
This could be serialized to YAML as:
from stringcase import camelcase
from jetblack_serialization.yaml import serialize, SerializerConfig
obj: Book = {
'author': 'Chairman Mao',
'book_id': 42,
'title': 'Little Red Book',
'publication_date': datetime(1973, 1, 1, 21, 52, 13),
'keywords': ['Revolution', 'Communism'],
'phrases': [
'Revolutionary wars are inevitable in class society',
'War is the continuation of politics'
],
'age': 24,
}
text = serialize(
obj,
Book,
SerializerConfig(key_serializer=camelcase, pretty_print=True)
)
print(text)
giving:
bookId: 42
title: Little Red Book
author: Chairman Mao
publicationDate: '1973-01-01T21:52:13.00Z'
keywords:
- Revolution
- Communism
phrases:
- Revolutionary wars are inevitable in class society
- War is the continuation of politics
age: 24
pages: null
Note the fields have been camel cased, and the publication date has been turned into an ISO 8601 date.
Deserializing YAML
We can deserialize the data as follows:
from stringcase import snakecase
from jetblack_serialization.yaml import deserialize, SerializerConfig
dct = deserialize(
text,
Annotated[Book, JSONValue()],
SerializerConfig(key_deserializer=snakecase)
)
XML
The XML version of the typed dictionary might look like this:
from datetime import datetime
from typing import Optional, TypedDict, Union
from typing_extensions import Annotated
from jetblack_serialization.xml import XMLEntity, XMLAttribute
class Book(TypedDict, total=False):
book_id: Annotated[int, XMLAttribute("bookId")]
title: str
author: str
publication_date: datetime
keywords: Annotated[list[Annotated[str, XMLEntity("Keyword")]], XMLEntity("Keywords")]
phrases: list[str]
age: Optional[Union[datetime, int]]
pages: Optional[int]
Note we have introduced some annotations to control the serialization. For XML we have used pascal-case to serialized the keys and snake-case for deserialization.
Serializing XML
To serialize we need to provide the containing tag Book:
from stringcase import pascalcase
from jetblack_serialization.xml import serialize, SerializerConfig
book: Book = {
'author': 'Chairman Mao',
'book_id': 42,
'title': 'Little Red Book',
'publication_date': datetime(1973, 1, 1, 21, 52, 13),
'keywords': ['Revolution', 'Communism'],
'phrases': [
'Revolutionary wars are inevitable in class society',
'War is the continuation of politics'
],
'age': 24,
'pages': None
}
text = serialize(
book,
Annotated[Book, XMLEntity("Book")],
SerializerConfig(key_serializer=pascalcase)
)
print(text)
Producing:
<Book bookId="42">
<Title>Little Red Book</Title>
<Author>Chairman Mao</Author>
<PublicationDate>1973-01-01T21:52:13.00Z</PublicationDate>
<Keywords>
<Keyword>Revolution</Keyword>
<Keyword>Communism</Keyword>
</Keywords>
<Phrase>Revolutionary wars are inevitable in class society</Phrase>
<Phrase>War is the continuation of politics</Phrase>
<Age>24</Age>
</Book>'
The annotations are more elaborate here. However, much of the typed dictionary requires no annotation.
First we needed the outer document wrapper XMLEntity("Book").
Next we annotated the book_id to be an XMLAttribute.
Finally we annotated the two lists differently. The keywords list used
a nested structure, which we indicated by giving the list a different
XMLEntity tag to the list items. For the phrases we used the default
in-line behaviour.
Deserializing XML
We can deserialize the XML as follows:
from stringcase import snakecase
from jetblack_serialization.xml import deserialize, SerializerConfig
dct = deserialize(
text,
Annotated[Book, XMLEntity("Book")],
SerializerConfig(key_deserializer=snakecase)
)
Attributes
For JSON, attributes are typically not required. However
JSONProperty(tag, JSONObject and JSONValue are provided for
completeness.
Contributing
To run the tests with tox and pyenv:
VIRTUALENV_DISCOVERY=pyenv tox
Release files for jetblack-serialization 4.0.13
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jetblack_serialization-4.0.13.tar.gz | 25.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jetblack_serialization-4.0.13-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.0 kB
Release files / jetblack_serialization-4.0.13.tar.gz
| Download URL | jetblack_serialization-4.0.13.tar.gz |
|---|---|
| Size | 25.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e09817f0f62a8f1e0d974dc26b6425c368bfbc71334c18d25036b7359c08e5e4
|
|
BLAKE2b-256 checksum How to use checksums |
c88b4d5f36744e2c24352a1c5af91cc0c27d1c6038314efa44b3d32773969aaf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Release files / jetblack_serialization-4.0.13-py3-none-any.whl
| Download URL | jetblack_serialization-4.0.13-py3-none-any.whl |
|---|---|
| Size | 32.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f34fc423743d0e8fc7afea450388b9cd03538eb8d4a91ef6ef7debd82d36a93d
|
|
BLAKE2b-256 checksum How to use checksums |
c66d26700cc4e690e0ce3a1b54ee4137d24d52e1c63568139640f06d04176f06
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|