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).
  • WildcardNotSupportedError — encode_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 */>.

Example

A runnable script is at examples/basic.py — start a server with just server, then:

python extensions/natsio-kvcodec/examples/basic.py

Metadata

Release files for natsio-kvcodec 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for natsio-kvcodec 0.1.1
File Size Uploaded Provenance
natsio_kvcodec-0.1.1.tar.gz 10.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for natsio-kvcodec 0.1.1
File Interpreter ABI Platform
natsio_kvcodec-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 22.0 kB

Release files / natsio_kvcodec-0.1.1.tar.gz

Download URL natsio_kvcodec-0.1.1.tar.gz
Size 10.0 kB
Tags Source
SHA-256 checksum
How to use checksums
086c9e1207b961b32b018df2557ad84bac4b4c902c05a10420803fb1b5221a2d
BLAKE2b-256 checksum
How to use checksums
d848c53ddc1287760038b71c38783ecce1f5f5a08060fff483b13f4a176b9eb5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / natsio_kvcodec-0.1.1-py3-none-any.whl

Download URL natsio_kvcodec-0.1.1-py3-none-any.whl
Size 12.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3e334e02ac3f918633a155f5e8257dc6851c9ed63516c7381032687dd9485b89
BLAKE2b-256 checksum
How to use checksums
a59546748c8c2a1dddc8de50c83cf24c60e30423aa39543f569ce417cddc52ed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for natsio-kvcodec 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for natsio_kvcodec-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

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