Skip to main content

zarr-vlen-ndarray

Typed variable-length ndarray data type (vlen-ndarray) for Zarr v3.

Each array element is a variable-length ndarray of shape (n, *inner_shape): the leading dimension n varies per element; the trailing inner_shape and the scalar dtype are fixed in the data type's configuration. One parameterized type covers, e.g., (n, 2) float32 centroid sets and (n,) uint64 location lists.

{
  "name": "vlen-ndarray",
  "configuration": {"dtype": "float32", "inner_shape": [2]}
}

The package provides:

  • VlenNDArray — a zarr-python ZDType for the data type above;
  • VlenNDArrayCodec — the paired parameter-free array -> bytes codec, which serializes each element as its raw little-endian C-order bytes and frames chunks exactly like zarr's vlen-bytes codec (numcodecs VLenBytes framing: u32le count, then per element u32le length + payload).

The normative extension text is in SPEC.md and the registry/ directory (zarr-extensions house style).

Why: byte identity with bytes + vlen-bytes

For any chunk, the encoded bytes are byte-identical to what zarr's vlen-bytes codec produces for the equivalent raw-bytes payloads (proved in tests/test_byte_identity.py, including through a zstd chain). A store that keeps ragged data as the bytes data type with raw-LE-bytes elements — the zagg-ragged/1 convention — can be upgraded to the typed form by rewriting zarr.json only; chunk objects are untouched. Downgrade is equally metadata-only, which is the escape hatch for readers without this package.

This package is phase 1 of englacial/zagg#210 and defines the element type for the zagg-ragged/2 store revision (englacial/zagg#340).

Install

From PyPI:

pip install zarr-vlen-ndarray

Or from source:

pip install git+https://github.com/espg/zarr-vlen-ndarray

Requires Python >= 3.11, zarr >= 3.1.0 (the ZDType API), numcodecs >= 0.14.

Usage

import numpy as np
import zarr
import zarr_vlen_ndarray  # registers the data type and codec
from zarr_vlen_ndarray import VlenNDArray, VlenNDArrayCodec

zdtype = VlenNDArray(dtype="float32", inner_shape=(2,))
arr = zarr.create_array(
    store="example.zarr",
    shape=(4,),
    chunks=(4,),
    dtype=zdtype,
    serializer=VlenNDArrayCodec(),   # required: zarr has no default serializer for extension dtypes
    compressors=zarr.codecs.ZstdCodec(level=3),
)

cells = np.empty(4, dtype=object)   # object-array staging, as with zarr's vlen types
cells[:] = [
    np.random.random((3, 2)).astype("float32"),
    np.empty((0, 2), dtype="float32"),          # empty cell
    np.random.random((7, 2)).astype("float32"),
    np.random.random((1, 2)).astype("float32"),
]
arr[:] = cells

arr[:][0]        # -> float32 ndarray of shape (3, 2)

Reading requires import zarr_vlen_ndarray first (see the registration section below); after that, plain zarr.open works.

Semantics worth knowing

  • Slice reads return object arrays whose cells are float32/uint64/... ndarrays. Decoded cells are read-only views over the decoded payload (zero-copy); call .copy() to mutate.
  • Scalar reads (arr[0]) return the cell wrapped in a 0-d object array — zarr-python does the same for its own vlen types. zarr_vlen_ndarray.unbox recovers the cell.
  • Fill values: the default fill is the empty cell (0, *inner_shape) (metadata fill_value: "", base64 of zero bytes). Cells materialized from the fill are VlenScalar instances — ndarray subclasses whose ==/!= compare the whole cell and return a plain bool (this is what makes zarr's empty-chunk elision work for ndarray cells; in every other respect they behave like regular ndarrays).

Registration and the no-package failure mode

The package declares both zarr entry points:

[project.entry-points."zarr.data_type"]
vlen-ndarray = "zarr_vlen_ndarray:VlenNDArray"

[project.entry-points."zarr.codecs"]
vlen-ndarray = "zarr_vlen_ndarray:VlenNDArrayCodec"

and also registers eagerly on import. Status with current zarr-python (3.1.0–3.2.1, pinned by tests/test_registration.py): the codec entry point is discovered lazily by zarr as designed, but zarr collects zarr.data_type entry points into the data type registry's lazy-load list without ever flushing it, so data type discovery via entry points is currently inert upstream. Practical rule: import zarr_vlen_ndarray before opening a store. When upstream flushes the lazy list, the explicit import becomes unnecessary automatically.

A vanilla zarr user without this package installed who opens a vlen-ndarray store gets (verbatim):

ValueError: No Zarr data type found that matches {'name': 'vlen-ndarray', 'configuration': {'dtype': 'float32', 'inner_shape': [2]}}

The fix is pip install zarr-vlen-ndarray + import zarr_vlen_ndarray — or, without installing anything, the metadata-only downgrade to bytes + vlen-bytes described above.

Registry status

The vlen-ndarray name is submitted but not yet registered with zarr-developers/zarr-extensions: see zarr-extensions#71. Until that PR merges, treat the name as provisional. The registry-formatted spec files in registry/ are the ones under review.

Development

uv sync --extra test
uv run pytest -v
uv run ruff check src tests && uv run ruff format --check src tests
uv run mypy src

CI runs the test matrix on Python 3.11–3.13 against latest zarr, plus a floor job against zarr==3.1.0.

License

MIT

Download files

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

Source Distribution

zarr_vlen_ndarray-0.1.2.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

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

zarr_vlen_ndarray-0.1.2-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

File details

Details for the file zarr_vlen_ndarray-0.1.2.tar.gz.

File metadata

  • Download URL: zarr_vlen_ndarray-0.1.2.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for zarr_vlen_ndarray-0.1.2.tar.gz
Algorithm Hash digest
SHA256 990c3070055f2ce619fbcf2662d7bcb02d7a1143b0e68f3a1503deabe462553b
MD5 0b0726d22390cf22df995deaeff3c367
BLAKE2b-256 296c051ca68b6a1538a14e354e9d6cb2477f1f2cb8a1af540fb8dccb2530653b

See more details on using hashes here.

Provenance

The following attestation bundles were made for zarr_vlen_ndarray-0.1.2.tar.gz:

Publisher: publish.yml on espg/zarr-vlen-ndarray

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

File details

Details for the file zarr_vlen_ndarray-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for zarr_vlen_ndarray-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0430de4c2cb6df01041059a2eae4c8d6fc1d845e54714e61eb9c146070d02006
MD5 b0dbd11a99340d6f03b63217f9f1b3e2
BLAKE2b-256 bfdb7a5ac752e0b3b034af0f5bea8987f3a4ea4e5d1b9cde510857f632cfa56d

See more details on using hashes here.

Provenance

The following attestation bundles were made for zarr_vlen_ndarray-0.1.2-py3-none-any.whl:

Publisher: publish.yml on espg/zarr-vlen-ndarray

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

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.2 This release

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page