Skip to main content

natsio-kvcodec

Transparent key/value codecs for natsio's KV store, over the core's KeyCodec / ValueCodec seam. Encode keys and values on the way in, decode them on the way out — get(), keys(), watch(), and history() all speak the decoded form while the bucket stores the encoded form.

Mirrors orbit.go/kvcodec, pythonized. Stdlib only; no runtime dependencies beyond natsio.

pip install natsio-kvcodec

Usage

Pass codecs to any create_key_value / key_value variant — the natsio core already accepts key_codec= and value_codec=:

from natsio.kv import KeyValueConfig
from natsio.kvcodec import PathKeyCodec, ZlibValueCodec

kv = await js.create_key_value(
    KeyValueConfig(bucket="cfg"),
    key_codec=PathKeyCodec(),      # "/app/db/url" stored as "app.db.url"
    value_codec=ZlibValueCodec(),  # values compressed at rest & over the wire
)

await kv.put("/app/db/url", b"postgres://localhost")
entry = await kv.get("/app/db/url")   # entry.key == "/app/db/url"
await kv.keys()                        # ["/app/db/url"] — DECODED keys

Key and value codecs are independent; use either, both, or neither.

Codecs

Key codecs (str -> str)

Codec What it does orbit.go parity
Base64KeyCodec Per-token raw URL-safe base64 (dots kept as separators). Lets a key carry characters illegal in NATS subjects — modulo the core-friction caveat below. Base64Codec (key side)
PathKeyCodec Filesystem keys /a/b/c <-> NATS a.b.c. Leading / becomes the _root_ sentinel, trailing / trimmed. PathCodec
NoOpKeyCodec Identity (the core's key_codec=None already means identity; useful as a chain filler). NoOpCodec
ChainKeyCodec(*codecs) Apply key codecs in sequence (encode first->last, decode last->first). KeyChainCodec

Every key codec guarantees its encoded output satisfies natsio.kv.validate_key (the raw URL-safe base64 alphabet and _root_ sentinel are all NATS-legal), so the core accepts the encoded key as a subject.

Base64KeyCodec, PathKeyCodec, NoOpKeyCodec, and an all-filterable ChainKeyCodec also implement encode_filter(pattern) (the core's runtime-checkable natsio.kv.FilterableKeyCodec protocol), which encodes a wildcard pattern while preserving */>. The natsio core calls this from watch(), so a wildcard watch under one of these codecs is encoded per token (orders.> -> b3JkZXJz.>) and works end-to-end — see Core Friction.

Value codecs (bytes -> bytes)

Codec What it does orbit.go parity
ZlibValueCodec(level=-1) Transparent DEFLATE via stdlib zlib. natsio addition
Base64ValueCodec Whole-value raw URL-safe base64. Base64Codec (value side)
NoOpValueCodec Identity. NoOpCodec
ChainValueCodec(*codecs) Apply value codecs in sequence. ValueChainCodec

ZlibValueCodec tradeoffs. It trades CPU for bytes, and small or incompressible values come out larger (a ~6-byte zlib envelope). It is not encryption. If you only want at-rest compression, prefer KeyValueConfig(compression=True) (server-side S2, zero client CPU); reach for this codec when you want the bytes compressed over the wire and counted in max_bytes.

Errors

Codecs fail loud (like orbit.go's error returns), never silently pass corrupt data through:

  • NoCodecsError — empty ChainKeyCodec() / ChainValueCodec().
  • KeyDecodeError / ValueDecodeError — corrupt/non-encoded input (a non-base64 token, a bad zlib stream).
  • WildcardNotSupportedErrorencode_filter on a chain with a non-filterable member.

All derive from KvCodecError.

orbit.go parity notes

  • Two classes per base64, not one. Go's structural typing lets a single Base64Codec satisfy both KeyCodec and ValueCodec. natsio's protocols have different encode signatures (str->str vs bytes->bytes), so this ships Base64KeyCodec and Base64ValueCodec.
  • Naming. orbit uses EncodeKey/DecodeKey; the natsio seam uses encode/decode, so codecs follow the natsio spelling.
  • ZlibValueCodec is new. orbit ships only base64 for values; a value codec is the natural home for compression, so natsio adds one.
  • Exact base64/path/filter test vectors are ported from orbit's codec_test.go / chain_codec_test.go, so behavior matches byte-for-byte (Base64KeyCodec().encode("test.key...") == "dGVzdA.a2V5...", etc.).
  • PathKeyCodec dot caveat (shared with orbit). It maps /<->. and cannot distinguish a literal . in the input from a separator, so feed it path-style keys; a.b decodes back as a/b.

Core friction

Building this extension stress-tested the codec seam. Two real gaps surfaced (neither is a codec bug — both are in the core, documented here so the behavior isn't surprising):

  1. The raw key is validated before the codec runs, defeating Base64's main use case. KeyValue._encode_key calls validate_key(raw_key) and then validate_key(codec.encode(raw_key)). So put("Acme Inc.contact", ...) with Base64KeyCodec raises InvalidKeyError on the space — even though the codec would turn it into the perfectly valid QWNtZSBJbmM.Y29udGFjdA. The escape- exotic-characters scenario from orbit's own README cannot work end-to-end. Proposal: when a key_codec is set, validate only the encoded key; the raw key is the user's domain and only the stored subject must be NATS-legal.

  2. keys() / iter_keys() (and purge_deletes()) still run the value codec on a payload the server deliberately stripped. Those paths use a headers-only (meta_only) watch, so every delivery has an empty payload — but _entry_from_msg unconditionally calls value_codec.decode(payload) for PUT entries. Any value codec that can't decode b"" (ZlibValueCodec, encryption, length-prefixed framing) makes keys() raise ValueDecodeError. Proposal: skip value decoding for headers-only deliveries (or when the payload is empty under meta_only). Pinned by a strict xfail in test_kvcodec_live.py::test_keys_under_framing_value_codec_is_broken.

A third one — the filter hook — is now closed. orbit's FilterableKeyCodec lets a wildcard watch encode tokens individually (orders.> -> b3JkZXJz.>). The natsio core mirrors this: watch() recognises the runtime-checkable natsio.kv.FilterableKeyCodec protocol (which the codecs here implement) and calls encode_filter(), so per-token wildcard watches work end-to-end. Under a codec the raw filter is the caller's domain (it may be in the codec's own notation, e.g. PathKeyCodec's /a/*) — only the encoded filter must be a legal subject filter. A wildcard watch under a non-filterable codec is still refused (ConfigError): encoding the whole key would mangle the */>.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

natsio_kvcodec-0.1.0.tar.gz (9.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

natsio_kvcodec-0.1.0-py3-none-any.whl (11.8 kB view details)

Uploaded Python 3

File details

Details for the file natsio_kvcodec-0.1.0.tar.gz.

File metadata

  • Download URL: natsio_kvcodec-0.1.0.tar.gz
  • Upload date:
  • Size: 9.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for natsio_kvcodec-0.1.0.tar.gz
Algorithm Hash digest
SHA256 400d92977e8aa773a4aadf4931968d8513632be2bc6dba9d55d519d432708a5b
MD5 c9736993c473d7b6280fdeffffc6968d
BLAKE2b-256 898f8b63361a2d807a0656257096a3dd1a7f34e5d048bb4655c364126f8dc913

See more details on using hashes here.

Provenance

The following attestation bundles were made for natsio_kvcodec-0.1.0.tar.gz:

Publisher: release-extension.yml on corruptmane/natsio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file natsio_kvcodec-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: natsio_kvcodec-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for natsio_kvcodec-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e03995bb1311bee969a7277e61c6053f58b3108da1ef5a3568bda95427dc5d4f
MD5 582b515c4e04fe3a12b2d0df421651ec
BLAKE2b-256 5cc28d7c35cb7f33422b28ce59e06443c76f10cedd1aba2569b976fbf513d73a

See more details on using hashes here.

Provenance

The following attestation bundles were made for natsio_kvcodec-0.1.0-py3-none-any.whl:

Publisher: release-extension.yml on corruptmane/natsio

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 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