ProvenPin Install

cattrs preconfigured orjson converter for attrs datetimes: working versions (tested 2026-10-16)

An attrs model with timezone-aware datetime fields serialized through cattrs' preconfigured orjson converter, showing native RFC 3339 handling and the hooks you still need to add.

passed5 passed · 0 failed2026-10-16 09:57 UTC
Status
passed
Last passed
2026-10-16 09:57 UTC
Tests
5 / 5
Language
Python
Runtime
Python 3.13.16
pinned versions4
attrs@26.1.0cattrs@26.2.1orjson@3.13.0pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt
.venv/bin/python -m pytest -q
test environment
Python 3.13.16
linux 6.17.0-1022-azure
x64
runner: github-actions 38883899161

The code

Exactly the files that passed. Your agent can pull them with get_recipe("cattrs-preconf-orjson-converter") (install), or see them on GitHub.

requirements.txt
attrs==26.1.0
cattrs==26.2.1
orjson==3.13.0
pytest==9.1.1
converter.py
from datetime import datetime

import attrs
from cattrs.preconf.orjson import make_converter


@attrs.define(frozen=True, slots=True)
class Session:
    id: int
    label: str
    started_at: datetime
    expires_at: datetime
    tags: list[str] = attrs.field(factory=list)


# the orjson preconf passes datetimes straight through to orjson and reads
# them back with datetime.fromisoformat, so RFC 3339 survives the round-trip
converter = make_converter()


def dump(session: Session) -> bytes:
    return converter.dumps(session)


def load(data: bytes | str) -> Session:
    return converter.loads(data, Session)
tests/test_converter.py
import json
from datetime import datetime, timedelta, time, timezone

import attrs
import cattrs
import orjson
import pytest
from cattrs.preconf.orjson import make_converter

from converter import Session, converter, dump, load


def make_session() -> Session:
    return Session(
        id=7,
        label="login",
        started_at=datetime(2026, 1, 2, 3, 4, 5, 123456, tzinfo=timezone.utc),
        expires_at=datetime(
            2026, 1, 2, 4, 4, 5, 123456, tzinfo=timezone(timedelta(hours=5, minutes=30))
        ),
        tags=["web", "mfa"],
    )


def test_roundtrip_preserves_aware_datetimes_and_microseconds():
    session = make_session()
    payload = dump(session)
    assert isinstance(payload, bytes)
    assert load(payload) == session
    assert load(payload).started_at.microsecond == 123456


def test_naive_datetimes_are_written_without_an_offset():
    session = Session(
        id=1,
        label="x",
        started_at=datetime(2026, 1, 2, 3, 4, 5),
        expires_at=datetime(2026, 1, 2, 3, 4, 5),
    )
    assert orjson.loads(dump(session))["started_at"] == "2026-01-02T03:04:05"
    assert load(dump(session)).started_at.tzinfo is None


def test_unstructure_keeps_datetime_objects_for_orjson():
    unstructured = converter.unstructure(make_session())
    assert isinstance(unstructured["started_at"], datetime)
    with pytest.raises(TypeError):
        json.dumps(unstructured)  # stdlib json has no datetime encoder here
    assert isinstance(converter.dumps(make_session()), bytes)


def test_time_values_dump_but_have_no_structure_hook():
    local = make_converter()

    @attrs.define
    class Slot:
        at: time

    payload = local.dumps(Slot(time(3, 4, 5)))
    assert payload == b'{"at":"03:04:05"}'
    with pytest.raises(cattrs.errors.StructureHandlerNotFoundError):
        local.loads(payload, Slot)
    local.register_structure_hook(time, lambda value, _: time.fromisoformat(value))
    assert local.loads(payload, Slot) == Slot(time(3, 4, 5))


def test_orjson_options_pass_through_to_dumps_only():
    session = make_session()
    payload = converter.dumps(session, option=orjson.OPT_INDENT_2)
    assert payload.startswith(b"{\n")
    assert load(payload) == session
pytest.ini
[pytest]
pythonpath = .

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.