orjson and msgspec encode/decode parity helpers: working versions (tested 2026-10-16)
Run orjson and msgspec side by side with canonical sort-key and non-str-key options, a shared Struct hook and typed decoding, and pin down where their bytes diverge.
passed6 passed · 0 failed2026-10-16 00:01 UTC- Status
- passed
- Last passed
- 2026-10-16 00:01 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38826982604
The code
Exactly the files that passed. Your agent can pull them with get_recipe("orjson-msgspec-encode-parity") (install), or see them on GitHub.
orjson==3.13.0 msgspec==0.22.0 pytest==9.1.1
from __future__ import annotations
from typing import Any
import msgspec
import orjson
def _hook(obj: Any) -> Any:
if isinstance(obj, msgspec.Struct):
return msgspec.to_builtins(obj)
raise TypeError(f"orjson cannot encode {type(obj).__name__}")
def orjson_bytes(obj: Any, *, sort_keys: bool = False) -> bytes:
option = orjson.OPT_NON_STR_KEYS | (orjson.OPT_SORT_KEYS if sort_keys else 0)
return orjson.dumps(obj, default=_hook, option=option)
def msgspec_bytes(obj: Any, *, sort_keys: bool = False) -> bytes:
return msgspec.json.encode(obj, order="sorted" if sort_keys else None)
def encode_both(obj: Any) -> tuple[bytes, bytes]:
return orjson_bytes(obj, sort_keys=True), msgspec_bytes(obj, sort_keys=True)
def assert_parity(obj: Any) -> None:
o, m = encode_both(obj)
if o != m:
raise AssertionError(f"orjson={o!r} msgspec={m!r}")
def decode_as(payload: bytes, type_: Any) -> Any:
return msgspec.json.decode(payload, type=type_)
import datetime as dt
import msgspec
import orjson
import pytest
from parity import (
assert_parity,
decode_as,
msgspec_bytes,
orjson_bytes,
)
def test_sorted_scalars_have_byte_parity():
payload = {"b": 1, "a": [1, 2.5, "x", True, None]}
o, m = orjson_bytes(payload, sort_keys=True), msgspec_bytes(payload, sort_keys=True)
assert o == m == b'{"a":[1,2.5,"x",true,null],"b":1}'
assert_parity(payload)
def test_utc_datetime_suffix_is_not_parity():
when = dt.datetime(2024, 1, 2, 3, 4, 5, tzinfo=dt.timezone.utc)
assert orjson_bytes(when, sort_keys=True) == b'"2024-01-02T03:04:05+00:00"'
assert msgspec_bytes(when, sort_keys=True) == b'"2024-01-02T03:04:05Z"'
with pytest.raises(AssertionError):
assert_parity({"at": when})
def test_int_keys_need_non_str_option():
with pytest.raises(TypeError):
orjson.dumps({1: "a"})
assert orjson_bytes({1: "a"}) == b'{"1":"a"}'
assert orjson_bytes({1: "a", 2: "b"}) == msgspec_bytes({1: "a", 2: "b"})
with pytest.raises(TypeError):
msgspec.json.encode({1: "a"}, order="sorted")
def test_non_finite_floats_collapse_to_null():
assert_parity({"nan": float("nan"), "inf": float("inf")})
assert msgspec.json.decode(msgspec_bytes({"x": float("nan")})) == {"x": None}
class User(msgspec.Struct):
name: str
age: int
def test_struct_encodes_via_hook_and_decodes_typed():
user = User("ada", 36)
assert orjson_bytes(user, sort_keys=True) == b'{"age":36,"name":"ada"}'
assert_parity(user)
assert decode_as(msgspec_bytes(user), User) == user
assert orjson.loads(orjson_bytes(user)) == {"name": "ada", "age": 36}
def test_decode_errors_share_value_error_base():
for decode in (orjson.loads, msgspec.json.decode):
with pytest.raises(ValueError):
decode(b"{bad")
[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.
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }{ "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.
Related stacks
msgspec Structs with tagged unions, constraints and fast codecs
Define msgspec Structs with tagged unions and Meta constraints, encode and decode JSON and MessagePack, inspect ValidationError paths, and convert plain dicts, all tested offline.
orjson + Pydantic v2 model round trip
Serialize Pydantic v2 models to bytes with orjson through a default fallback and option flags, then validate them back offline with TypeAdapter.
SQLAlchemy JSON columns serialized with orjson
Wire orjson dumps/loads into the SQLAlchemy engine so dict and list columns stay single-encoded JSON, with mutation tracking gotchas, tested on in-memory SQLite.