Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

paperjson-0.2.0.tar.gz (5.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

paperjson-0.2.0-py3-none-any.whl (6.7 kB view details)

Uploaded Python 3

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

Hashes for paperjson-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1b6c25a722ae5efd9925ae71593bd89d4d43c90befefef53c4b3b2540e47ed04
MD5 b12542c4fcbe0ffedbb3f3c1da88ebe6
BLAKE2b-256 4455a712036847f85ba6ddbf6e983876c0f7e0156c861093eba68878f85c608f

See more details on using hashes here.

Provenance

The following attestation bundles were made for paperjson-0.2.0.tar.gz:

Publisher: publish.yml on timrburnham/paperjson

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for paperjson-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3502c55205f9d27e60b92d56520435c20c22288c89bd5897407bf8ee1f3a56dd
MD5 9629ba2cd66f917cfac712cffe662023
BLAKE2b-256 16f363507dafa4fa3248dd7b3935c7445e6085cbb5421d7608ca502ffc7f4345

See more details on using hashes here.

Provenance

The following attestation bundles were made for paperjson-0.2.0-py3-none-any.whl:

Publisher: publish.yml on timrburnham/paperjson

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page