Skip to main content

dr-serialize

CI PyPI

Repo Definitions Terms TOML Contracts TOML

dr-serialize normalizes Python values into JSON-encodable data and produces deterministic JSON text, bytes, hashes, and identities. Its functionality is organized into four areas supported by shared infrastructure:

  • Normalization converts Python values into bounded, JSON-shaped data through extensible conversion rules for diagnostics and storage. Non-finite floats may survive normalization outside canonical set ordering.
  • Canonical JSON renders bounded finite strict JSON values as deterministic text and exact UTF-8 bytes, projects unordered collections into stable arrays, and produces validated SHA-256 digests.
  • Strict decoding parses one complete UTF-8 JSON value under explicit byte and depth limits while rejecting duplicate keys, non-finite numbers, and malformed or trailing input.
  • Identity validates a fixed document shape around a domain-owned payload and derives stable canonical bytes and a full identity hash without normalization.
  • Infra provides the contracts shared by those areas:
    • recursive JSON values and iterative strict validation;
    • validated full SHA-256 digests;
    • diagnostic paths, typed errors, and bounded metadata;
    • a common UTF-8 encoding invariant.

The declarations below are abbreviated contract shapes; ... replaces implementation details.

Normalization

Normalization is policy-driven and may be lossy. A Serializer combines explicit depth and size limits with an ordered chain of consumer handlers, and produces JSON-encodable, Jsonable-shaped data for diagnostics or storage rather than identity. Non-finite floats may survive normal conversion outside canonical set ordering.

class SerializationLimits(BaseModel):
    max_depth: int = 200
    max_bytes: int
    hard_max_bytes: int | None = None


def postgres_jsonb_limits(
    max_bytes: int = POSTGRES_JSONB_PAYLOAD_MAX_BYTES,
) -> SerializationLimits: ...
type JsonableHandle = tuple[bool, Any]
type JsonableHandler = Callable[
    [Any, ConversionContext],
    JsonableHandle,
]


@dataclass(frozen=True, slots=True)
class ConversionContext:
    serializer: Serializer
    depth: int
    path: JsonPath

    def convert(
        self,
        child: Any,
        key: str | int | None = None,
    ) -> Jsonable: ...


@dataclass(frozen=True, slots=True)
class Serializer:
    limits: SerializationLimits
    handlers: tuple[JsonableHandler, ...] = ()

    def to_jsonable(self, x: Any) -> Jsonable: ...

Canonical JSON

Canonical JSON consumes finite strict JSON values without applying handlers or selecting domain fields. Profile v1 admits at most 200 nested containers and 640 decimal digits per integer; scalars have depth 0 and a root list or object has depth 1. It then uses the standard-library JSON encoder; canonical text is the stable contract from which exact bytes and hashes are derived.

CANONICAL_JSON_MAX_CONTAINER_DEPTH: Final[int] = 200
CANONICAL_JSON_MAX_INTEGER_DIGITS: Final[int] = 640


def canonical_json(value: Jsonable) -> str: ...
def canonical_json_bytes(value: Jsonable, /) -> bytes: ...


def json_hash(
    value: Jsonable,
    *,
    length: int | None = None,
) -> Sha256Digest | str: ...
def canonical_sorted_values(
    values: Iterable[Jsonable],
    /,
) -> list[Jsonable]: ...

canonical_sorted_values projects only logically unordered collections into a stable array. It does not reorder arrays whose existing order is meaningful.

Strict decoding

Strict decoding accepts exactly one bounded UTF-8 JSON value without coercion. Failure messages, structured diagnostics, and exception cause and context do not echo or retain input. Traceback locals are outside this guarantee.

def decode_strict_json_bytes(
    data: bytes,
    /,
    *,
    max_bytes: int,
    max_depth: int,
) -> Jsonable: ...
class StrictJsonDecodeError(SerializationError): ...


class JsonByteLimitError(StrictJsonDecodeError): ...
class JsonDepthLimitError(StrictJsonDecodeError): ...
class InvalidUtf8Error(StrictJsonDecodeError): ...
class JsonSyntaxError(StrictJsonDecodeError): ...
class DuplicateJsonKeyError(StrictJsonDecodeError): ...
class NonFiniteJsonNumberError(StrictJsonDecodeError): ...

Identity

The owning domain supplies every identity-bearing fact. dr-serialize validates the fixed document envelope against the same complete Canonical JSON Text profile, applies copy.deepcopy during construction and payload access, and derives canonical identity bytes and a full hash without normalization. Accepted custom container subclasses control whether the deep-copy protocol yields alias isolation.

class IdentityDocument:
    schema: str
    schema_version: int

    def __init__(
        self,
        schema: str,
        schema_version: int,
        payload: Jsonable,
    ) -> None: ...

    @property
    def payload(self) -> Jsonable: ...

    def to_json_dict(self) -> dict[str, Jsonable]: ...
def build_identity_document(
    *,
    schema: str,
    schema_version: int,
    payload: Any,
) -> IdentityDocument: ...


def validate_identity_document(
    document: dict[Any, Any],
) -> IdentityDocument: ...


def canonical_identity_json_bytes(
    document: IdentityDocument,
    /,
) -> bytes: ...


def identity_document_hash(
    document: IdentityDocument,
) -> Sha256Digest: ...

Shared infrastructure

The shared infrastructure defines the recursive value, digest, and diagnostic contracts used across the four functional areas. Finite-number validation is a runtime property of strict Jsonable values because Python's type system cannot express it in the recursive alias.

type Jsonable = (
    None
    | bool
    | int
    | float
    | str
    | list[Jsonable]
    | dict[str, Jsonable]
)


def validate_strict_json(value: Any) -> Jsonable: ...
class Sha256Digest(str):
    @classmethod
    def parse(cls, value: str, /) -> Self: ...


type JsonPath = tuple[str | int, ...]


class SerializationError(Exception):
    path: JsonPath
    detail: str

    def diagnostics(self) -> dict[str, Any]: ...

Development

Install dependencies and the commit hook once per clone:

uv sync --locked
uv run pre-commit install

The hook runs scripts/pre-check.sh for Ruff formatting, Ruff lint, and type checking, followed by the test suite.

Metadata

Release files for dr-serialize 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dr-serialize 0.1.2
File Size Uploaded
dr_serialize-0.1.2.tar.gz 17.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dr-serialize 0.1.2
File Interpreter ABI Platform
dr_serialize-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 45.4 kB

Release files / dr_serialize-0.1.2.tar.gz

Download URL dr_serialize-0.1.2.tar.gz
Size 17.9 kB
Tags Source
SHA-256 checksum
How to use checksums
02662cbb9ad3f1262a81bc14a2f3254f925f880333da69eac6dbda2226d1c51f
BLAKE2b-256 checksum
How to use checksums
5e2a25dd5859ddfd78ee604a59c6ab81a0601669506a6af6ea871fc4438955bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.

Transparency log

Release files / dr_serialize-0.1.2-py3-none-any.whl

Download URL dr_serialize-0.1.2-py3-none-any.whl
Size 27.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
785015ceb779906bd03965fd541d1733772b45fefbd2d5473304b7f5db60ce5d
BLAKE2b-256 checksum
How to use checksums
ccb7511d474c07440ff8de4c78aa637a461746c5a5dca9e539fca06b2d015722
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page