cbor2 CBOR encode/decode with semantic tags: working versions (tested 2026-10-18)
Round-trip datetimes, exact Decimals and custom CBOR semantic tags with cbor2 6.x, using the encoder-based default hook, the two-argument tag_hook and canonical encoding.
passed6 passed · 0 failed2026-10-18 03:56 UTC- Status
- passed
- Last passed
- 2026-10-18 03:56 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
pinned versions2
cbor2@6.1.5pytest@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 39095370682
The code
Exactly the files that passed. Your agent can pull them with get_recipe("cbor2-encode-decode-tags") (install), or see them on GitHub.
requirements.txt
cbor2==6.1.5 pytest==9.1.1
cbor_codec.py
from __future__ import annotations
from typing import Any
import cbor2
from cbor2 import CBORTag
POINT_TAG = 40001
class Point:
def __init__(self, x: int, y: int) -> None:
self.x = x
self.y = y
def __eq__(self, other: object) -> bool:
return isinstance(other, Point) and (self.x, self.y) == (other.x, other.y)
def __repr__(self) -> str:
return f"Point({self.x}, {self.y})"
def _default(encoder: cbor2.CBOREncoder, obj: Any) -> None:
# cbor2 6.x passes the encoder: encode through it, do not return a value.
if isinstance(obj, Point):
encoder.encode_semantic(POINT_TAG, [obj.x, obj.y])
else:
raise cbor2.CBOREncodeTypeError(f"cannot encode {type(obj).__name__}")
def _tag_hook(tag: CBORTag, immutable: bool) -> Any:
if tag.tag == POINT_TAG:
x, y = tag.value
return Point(x, y)
return tag
def encode(obj: Any, *, canonical: bool = False, timezone=None) -> bytes:
return cbor2.dumps(obj, default=_default, canonical=canonical, timezone=timezone)
def decode(data: bytes) -> Any:
return cbor2.loads(data, tag_hook=_tag_hook)
tests/test_cbor_codec.py
from datetime import datetime, timedelta, timezone
from decimal import Decimal
import cbor2
import pytest
from cbor2 import CBORTag
from cbor_codec import POINT_TAG, Point, decode, encode
def test_datetime_roundtrip_preserves_offset():
dt = datetime(2021, 1, 1, 12, 0, tzinfo=timezone(timedelta(hours=5, minutes=30)))
assert decode(encode(dt)) == dt
def test_naive_datetime_needs_timezone():
naive = datetime(2021, 1, 1, 12, 0)
with pytest.raises(cbor2.CBOREncodeError):
encode(naive)
assert decode(encode(naive, timezone=timezone.utc)) == naive.replace(tzinfo=timezone.utc)
def test_decimal_roundtrip_is_exact():
result = decode(encode(Decimal("1.230")))
assert result == Decimal("1.230")
assert str(result) == "1.230" # trailing zero survives, unlike a float roundtrip
def test_custom_tag_roundtrip_and_unknown_passthrough():
assert decode(encode(Point(3, 4))) == Point(3, 4)
assert decode(cbor2.dumps(CBORTag(999, "hi"))) == CBORTag(999, "hi")
def test_default_return_value_is_ignored():
# default(encoder, value) must write via the encoder; a returned value is
# dropped, leaving a truncated stream (empty when the root object is custom).
out = cbor2.dumps(
Point(1, 2), default=lambda enc, obj: CBORTag(POINT_TAG, [obj.x, obj.y])
)
assert out == b""
def test_canonical_encoding_is_insertion_order_independent():
a = {"b": 1, "aa": 2}
b = {"aa": 2, "b": 1}
assert encode(a) != encode(b)
assert encode(a, canonical=True) == encode(b, canonical=True)
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.