Paper-thin JSON serialization/deserialization for Python dataclasses
Project description
paperjson
Paper-thin JSON serialization/deserialization for Python dataclasses. Easy to extend for custom classes.
Overview
paperjson recursively serializes dataclass fields to JSON and reconstructs
them on deserialization. Fields with types like datetime, Path, Decimal,
or any other non-JSON-native type are automatically handled.
Automatic stringification: When the serializer encounters a type it doesn't
explicitly know about, it calls str() on the value and attempts a round-trip
test — it calls Type(str_value) and checks whether the result equals the
original. If the round-trip succeeds, str() is auto-registered for that type,
so subsequent calls skip the check. If the round-trip fails, a TypeError is
raised telling you to register a custom serializer.
You can always override the fallback by registering explicit serializers and deserializers for your own types (see Custom type support).
Usage
There are two ways to add to_json() / from_json() to a dataclass:
1A. Inherit from PaperJsonBase
Inheriting from PaperJsonBase gives full type-checker / LSP support — your
editor will suggest to_json() and from_json():
from dataclasses import dataclass
import paperjson
@dataclass
class User(paperjson.PaperJsonBase):
name: str
email: str
user = User(name="Alice", email="alice@example.com")
print(user.to_json())
# {"name": "Alice", "email": "alice@example.com"}
restored = User.from_json(user.to_json())
print(restored == user)
# True
This is similar to Pydantic BaseModel. But! You might not wish to add a base to your class.
1B. Use the @serdes decorator
Decorate any dataclass to inject the methods at runtime. It works identically, but type checkers can't see to_json() / from_json():
from dataclasses import dataclass
import paperjson
@paperjson.serdes
@dataclass
class User:
name: str
email: str
user = User(name="Alice", email="alice@example.com")
print(user.to_json()) # type: ignore
# {"name": "Alice", "email": "alice@example.com"}
2. Type annotations with PaperJsonProtocol
Use PaperProtocol in function signatures to accept anything that has
to_json() / from_json() — whether it inherits from PaperJsonBase
or was decorated:
from typing import Any
import paperjson
def dump(obj: paperjson.PaperJsonProtocol[Any]) -> str:
return obj.to_json(indent=2)
def load(cls: type[paperjson.PaperJsonProtocol[Any]], data: str) -> Any:
return cls.from_json(data)
3. Custom type support
Register serializers and deserializers for any type that stringification can't handle, or when you need explicit control over the JSON representation.
from decimal import Decimal
import paperjson
@paperjson.register_serializer(Decimal)
def _(val: Decimal) -> str:
return str(val)
@paperjson.register_deserializer(Decimal)
def _(val: str) -> Decimal:
return Decimal(val)
Note: For a type like
Decimal, the automatic stringification would actually succeed (d == Decimal(str(d)) == True), but registering explicitly is clearer.
4. Worked example
from datetime import datetime, timezone
from pathlib import Path
from dataclasses import dataclass
import paperjson
@dataclass
class Address(paperjson.PaperJsonBase):
line1: str
line2: str
city: str
st: str
zip: str
@paperjson.serdes
@dataclass
class User():
name: str
dob: datetime
email: str
homedir: Path
mail: Address
obj = User(
name="Alice",
dob=datetime.now(timezone.utc),
email="alice@example.com",
homedir=Path.home(),
mail=Address("123 Main St", "", "Springfield", "IL", "62701"),
)
json_str = obj.to_json()
restored = User.from_json(json_str)
Output dataclasses are identical to those created:
>>> print(restored)
User(name='Alice', dob=datetime.datetime(2026, 5, 19, 4, 50, 7, 485835, tzinfo=datetime.timezone.utc), email='alice@example.com', homedir=PosixPath('/home/alice'), mail=Address(line1='123 Main St', line2='', city='Springfield', st='IL', zip='62701'))
>>> obj == restored
True
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file paperjson-0.2.0.tar.gz.
File metadata
- Download URL: paperjson-0.2.0.tar.gz
- Upload date:
- Size: 5.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b6c25a722ae5efd9925ae71593bd89d4d43c90befefef53c4b3b2540e47ed04
|
|
| MD5 |
b12542c4fcbe0ffedbb3f3c1da88ebe6
|
|
| BLAKE2b-256 |
4455a712036847f85ba6ddbf6e983876c0f7e0156c861093eba68878f85c608f
|
Provenance
The following attestation bundles were made for paperjson-0.2.0.tar.gz:
Publisher:
publish.yml on timrburnham/paperjson
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
paperjson-0.2.0.tar.gz -
Subject digest:
1b6c25a722ae5efd9925ae71593bd89d4d43c90befefef53c4b3b2540e47ed04 - Sigstore transparency entry: 1589943871
- Sigstore integration time:
-
Permalink:
timrburnham/paperjson@7b828bc1c427c748098204b26c1b3aedac21d60f -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/timrburnham
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7b828bc1c427c748098204b26c1b3aedac21d60f -
Trigger Event:
release
-
Statement type:
File details
Details for the file paperjson-0.2.0-py3-none-any.whl.
File metadata
- Download URL: paperjson-0.2.0-py3-none-any.whl
- Upload date:
- Size: 6.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3502c55205f9d27e60b92d56520435c20c22288c89bd5897407bf8ee1f3a56dd
|
|
| MD5 |
9629ba2cd66f917cfac712cffe662023
|
|
| BLAKE2b-256 |
16f363507dafa4fa3248dd7b3935c7445e6085cbb5421d7608ca502ffc7f4345
|
Provenance
The following attestation bundles were made for paperjson-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on timrburnham/paperjson
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
paperjson-0.2.0-py3-none-any.whl -
Subject digest:
3502c55205f9d27e60b92d56520435c20c22288c89bd5897407bf8ee1f3a56dd - Sigstore transparency entry: 1589944117
- Sigstore integration time:
-
Permalink:
timrburnham/paperjson@7b828bc1c427c748098204b26c1b3aedac21d60f -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/timrburnham
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7b828bc1c427c748098204b26c1b3aedac21d60f -
Trigger Event:
release
-
Statement type: