dataclasses-json camelCase serialization: working versions (tested 2026-10-16)
Serialize dataclasses to camelCase JSON with dataclasses-json, handling nested types, datetimes and unknown keys via LetterCase and Undefined.
passed6 passed · 0 failed2026-10-16 21:56 UTC- Status
- passed
- Last passed
- 2026-10-16 21:56 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
pinned versions2
dataclasses-json@0.6.7pytest@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 38972656245
The code
Exactly the files that passed. Your agent can pull them with get_recipe("dataclasses-json-camelcase") (install), or see them on GitHub.
requirements.txt
dataclasses-json==0.6.7 pytest==9.1.1
models.py
from dataclasses import dataclass, field
from datetime import datetime
from dataclasses_json import (
CatchAll,
LetterCase,
Undefined,
dataclass_json,
)
@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass
class Address:
street_name: str
zip_code: str
@dataclass
class Contact:
# Left undecorated on purpose: LetterCase does not reach nested classes.
phone_number: str
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.RAISE)
@dataclass
class User:
user_id: int
full_name: str
created_at: datetime
address: Address
contact: Contact
tags: list[str] = field(default_factory=list)
@dataclass_json(letter_case=LetterCase.CAMEL)
@dataclass
class Note:
note_id: int
body: str
@dataclass_json(letter_case=LetterCase.CAMEL, undefined=Undefined.INCLUDE)
@dataclass
class Webhook:
event_id: str
rest: CatchAll = None
tests/test_serialization.py
import json
from datetime import datetime, timezone
import pytest
from dataclasses_json.undefined import UndefinedParameterError
from models import Address, Contact, Note, User, Webhook
def make_user() -> User:
return User(
user_id=1,
full_name="Ada Lovelace",
created_at=datetime(2026, 1, 2, 3, 4, 5, tzinfo=timezone.utc),
address=Address("Main St", "N1 1AA"),
contact=Contact("555-0100"),
tags=["math"],
)
def test_camel_case_keys_and_aware_roundtrip():
user = make_user()
payload = json.loads(user.to_json())
assert set(payload) == {"userId", "fullName", "createdAt", "address", "contact", "tags"}
assert user.to_dict()["address"] == {"streetName": "Main St", "zipCode": "N1 1AA"}
assert User.from_json(user.to_json()) == user
def test_undecorated_nested_class_keeps_snake_case():
payload = json.loads(make_user().to_json())
assert payload["contact"] == {"phone_number": "555-0100"}
def test_datetime_is_encoded_as_epoch_seconds():
payload = json.loads(make_user().to_json())
assert isinstance(payload["createdAt"], float)
with pytest.raises(TypeError):
User.from_dict({**payload, "createdAt": "2026-01-02T03:04:05+00:00"})
def test_naive_datetime_comes_back_timezone_aware():
user = make_user()
user.created_at = datetime(2026, 1, 2, 3, 4, 5)
restored = User.from_json(user.to_json())
assert restored.created_at.tzinfo is not None
assert restored != user
def test_undefined_keys_are_ignored_or_raise():
assert Note.from_dict({"noteId": 1, "body": "hi", "typo": True}).body == "hi"
with pytest.raises(UndefinedParameterError):
User.from_dict({**json.loads(make_user().to_json()), "typo": True})
def test_catch_all_collects_extras():
hook = Webhook.from_dict({"eventId": "e1", "source": "github", "attempt": 2})
assert hook.rest == {"source": "github", "attempt": 2}
assert json.loads(hook.to_json()) == {"eventId": "e1", "source": "github", "attempt": 2}
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
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.