# jetblack-serialization
Serialization for JSON and XML in Python using typing annotations
(read the [docs](https://rob-blackbourn.github.io/jetblack-serialization/)).
## Status
It has been tested with Python 3.7 used the `typing_extensions`
package for `TypedDict` and `Annotated`. In Python 3.8 the `TypedDict`
class is available in the standard `typing` package.
## Installation
The package can be installed with pip.
```bash
pip install jetblack-serialization
```
## Overview
The package adds support for type annotations when serializing or deserializing
JSON or XML.
### JSON
Given a typed dictionary:
```python
from datetime import datetime
from typing import List, 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
This could be serialized to JSON as:
```python
from stringcase import camelcase, snakecase
from jetblack_serialization import SerializerConfig
from jetblack_serialization.json import serialize
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(camelcase, snakecase, pretty_print=True)
)
print(text)
```
giving:
```json
{
"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
We can deserialize the data as follows:
```python
from stringcase import camelcase, snakecase
from jetblack_serialization import SerializerConfig
from jetblack_serialization.json import deserialize
dct = deserialize(
text,
Annotated[Book, JSONValue()],
SerializerConfig(camelcase, snakecase)
)
```
### XML
The XML version of the typed dictionary might look like this:
```python
from datetime import datetime
from typing import List, 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
To serialize we need to provide the containing tag `Book`:
```python
from stringcase import pascalcase, snakecase
from jetblack_serialization import SerializerConfig
from jetblack_serialization.xml import serialize
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(pascalcase, snakecase)
)
print(text)
```
Producing:
```xml
<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
We can deserialize the XML as follows:
```python
from stringcase import pascalcase, snakecase
from jetblack_serialization import SerializerConfig
from jetblack_serialization.xml import deserialize
dct = deserialize(
text,
Annotated[Book, XMLEntity("Book")],
SerializerConfig(pascalcase, snakecase)
)
```
## Attributes
For JSON, attributes are typically not required. However
`JSONProperty(tag: str)` and `JSONValue()` are provided for
completeness.
Raw data
{
"_id": null,
"home_page": "https://github.com/rob-blackbourn/jetblack-serialization",
"name": "jetblack-serialization",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.7",
"maintainer_email": null,
"keywords": "serialization, jetblack, json, xml, typing",
"author": "Rob Blackbourn",
"author_email": "rob.blackbourn@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/ef/c5/73c652615bcc23c136aed53b11cb000b2d535ebd431a5ed0427f2c982868/jetblack-serialization-3.1.1.tar.gz",
"platform": null,
"description": "# jetblack-serialization\n\nSerialization for JSON and XML in Python using typing annotations\n(read the [docs](https://rob-blackbourn.github.io/jetblack-serialization/)).\n\n## Status\n\nIt has been tested with Python 3.7 used the `typing_extensions`\npackage for `TypedDict` and `Annotated`. In Python 3.8 the `TypedDict`\nclass is available in the standard `typing` package.\n\n## Installation\n\nThe package can be installed with pip.\n\n```bash\npip install jetblack-serialization\n```\n\n## Overview\n\nThe package adds support for type annotations when serializing or deserializing\nJSON or XML.\n\n\n### JSON\n\nGiven a typed dictionary:\n\n```python\nfrom datetime import datetime\nfrom typing import List, Optional, TypedDict, Union\n\nclass Book(TypedDict, total=False):\n book_id: int\n title: str\n author: str\n publication_date: datetime\n keywords: List[str]\n phrases: List[str]\n age: Optional[Union[datetime, int]]\n pages: Optional[int]\n```\n\n#### Serializing\n\nThis could be serialized to JSON as:\n\n```python\nfrom stringcase import camelcase, snakecase\nfrom jetblack_serialization import SerializerConfig\nfrom jetblack_serialization.json import serialize\n\nobj: Book = {\n 'author': 'Chairman Mao',\n 'book_id': 42,\n 'title': 'Little Red Book',\n 'publication_date': datetime(1973, 1, 1, 21, 52, 13),\n 'keywords': ['Revolution', 'Communism'],\n 'phrases': [\n 'Revolutionary wars are inevitable in class society',\n 'War is the continuation of politics'\n ],\n 'age': 24,\n}\ntext = serialize(\n obj,\n Book,\n SerializerConfig(camelcase, snakecase, pretty_print=True)\n)\nprint(text)\n```\n\ngiving:\n\n```json\n{\n \"bookId\": 42,\n \"title\": \"Little Red Book\",\n \"author\": \"Chairman Mao\",\n \"publicationDate\": \"1973-01-01T21:52:13.00Z\",\n \"keywords\": [\"Revolution\", \"Communism\"],\n \"phrases\": [\"Revolutionary wars are inevitable in class society\", \"War is the continuation of politics\"],\n \"age\": 24,\n \"pages\": null\n}\n```\n\nNote the fields have been camel cased, and the publication date has been turned\ninto an ISO 8601 date.\n\n#### Deserializing\n\nWe can deserialize the data as follows:\n\n```python\nfrom stringcase import camelcase, snakecase\nfrom jetblack_serialization import SerializerConfig\nfrom jetblack_serialization.json import deserialize\n\ndct = deserialize(\n text,\n Annotated[Book, JSONValue()],\n SerializerConfig(camelcase, snakecase)\n)\n```\n\n### XML\n\nThe XML version of the typed dictionary might look like this:\n\n```python\nfrom datetime import datetime\nfrom typing import List, Optional, TypedDict, Union\nfrom typing_extensions import Annotated\nfrom jetblack_serialization.xml import XMLEntity, XMLAttribute\n\nclass Book(TypedDict, total=False):\n book_id: Annotated[int, XMLAttribute(\"bookId\")]\n title: str\n author: str\n publication_date: datetime\n keywords: Annotated[List[Annotated[str, XMLEntity(\"Keyword\")]], XMLEntity(\"Keywords\")]\n phrases: List[str]\n age: Optional[Union[datetime, int]]\n pages: Optional[int]\n```\n\nNote we have introduced some annotations to control the serialization.\nFor XML we have used pascal-case to serialized the keys and snake-case\nfor deserialization.\n\n#### Serializing\n\nTo serialize we need to provide the containing tag `Book`:\n\n```python\nfrom stringcase import pascalcase, snakecase\nfrom jetblack_serialization import SerializerConfig\nfrom jetblack_serialization.xml import serialize\n\nbook: Book = {\n 'author': 'Chairman Mao',\n 'book_id': 42,\n 'title': 'Little Red Book',\n 'publication_date': datetime(1973, 1, 1, 21, 52, 13),\n 'keywords': ['Revolution', 'Communism'],\n 'phrases': [\n 'Revolutionary wars are inevitable in class society',\n 'War is the continuation of politics'\n ],\n 'age': 24,\n 'pages': None\n}\ntext = serialize(\n book,\n Annotated[Book, XMLEntity(\"Book\")],\n SerializerConfig(pascalcase, snakecase)\n)\nprint(text)\n```\n\nProducing:\n\n```xml\n<Book bookId=\"42\">\n <Title>Little Red Book</Title>\n <Author>Chairman Mao</Author>\n <PublicationDate>1973-01-01T21:52:13.00Z</PublicationDate>\n <Keywords>\n <Keyword>Revolution</Keyword>\n <Keyword>Communism</Keyword>\n </Keywords>\n <Phrase>Revolutionary wars are inevitable in class society</Phrase>\n <Phrase>War is the continuation of politics</Phrase>\n <Age>24</Age>\n</Book>'\n```\n\nThe annotations are more elaborate here. However, much of the typed dictionary\nrequires no annotation.\n\nFirst we needed the outer document wrapper `XMLEntity(\"Book\")`.\n\nNext we annotated the `book_id` to be an `XMLAttribute`.\n\nFinally we annotated the two lists differently. The `keywords` list used\na nested structure, which we indicated by giving the list a different\n`XMLEntity` tag to the list items. For the phrases we used the default\nin-line behaviour.\n\n#### Deserializing\n\nWe can deserialize the XML as follows:\n\n```python\nfrom stringcase import pascalcase, snakecase\nfrom jetblack_serialization import SerializerConfig\nfrom jetblack_serialization.xml import deserialize\n\ndct = deserialize(\n text,\n Annotated[Book, XMLEntity(\"Book\")],\n SerializerConfig(pascalcase, snakecase)\n)\n```\n\n## Attributes\n\nFor JSON, attributes are typically not required. However\n`JSONProperty(tag: str)` and `JSONValue()` are provided for\ncompleteness.",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Serialization for JSON and XML using typing",
"version": "3.1.1",
"project_urls": {
"Homepage": "https://github.com/rob-blackbourn/jetblack-serialization",
"Repository": "https://github.com/rob-blackbourn/jetblack-serialization"
},
"split_keywords": [
"serialization",
" jetblack",
" json",
" xml",
" typing"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "e58336ef715c0dfa96d8ca0cca6c7a16c1276bde5ae47d5c473016dbc7688b64",
"md5": "c9ad4c56e55093ce4b473b4e48d8297c",
"sha256": "334b049a3eb916a425dec95a079372d1f8f9adc466c7177000bf8dd517996e05"
},
"downloads": -1,
"filename": "jetblack_serialization-3.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c9ad4c56e55093ce4b473b4e48d8297c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.7",
"size": 25768,
"upload_time": "2024-06-19T13:26:46",
"upload_time_iso_8601": "2024-06-19T13:26:46.320765Z",
"url": "https://files.pythonhosted.org/packages/e5/83/36ef715c0dfa96d8ca0cca6c7a16c1276bde5ae47d5c473016dbc7688b64/jetblack_serialization-3.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "efc573c652615bcc23c136aed53b11cb000b2d535ebd431a5ed0427f2c982868",
"md5": "701f49588c218cb568cbde288d587088",
"sha256": "ee06e5856953f8641fba46a850231da1c96892f91053fdd86b25792c6925db1c"
},
"downloads": -1,
"filename": "jetblack-serialization-3.1.1.tar.gz",
"has_sig": false,
"md5_digest": "701f49588c218cb568cbde288d587088",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.7",
"size": 19012,
"upload_time": "2024-06-19T13:26:44",
"upload_time_iso_8601": "2024-06-19T13:26:44.238888Z",
"url": "https://files.pythonhosted.org/packages/ef/c5/73c652615bcc23c136aed53b11cb000b2d535ebd431a5ed0427f2c982868/jetblack-serialization-3.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-06-19 13:26:44",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "rob-blackbourn",
"github_project": "jetblack-serialization",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "jetblack-serialization"
}