neu_vol.backends.base

Backend protocol and spec-based opener.

The block-map engine is backend-agnostic: it only needs to read and write rectangular regions and know a store’s shape/dtype/chunks. Concrete backends (TensorStore for zarr v3 + precomputed, tifffile/imageio for image stacks, h5py for HDF5 shards) implement ArrayBackend.

Backends are opened from a JSON-serializable spec (a plain dict). This is the key to dask: a per-block task ships the spec (paths + params), not an open handle, and reopens the backend on the worker.

Attributes

Classes

ArrayBackend

Minimal chunked-array interface the engine depends on.

Functions

clear_backend_cache() → None

Drop all cached backends.

open_backend(spec) → ArrayBackend

Open a backend from a serializable spec (cached per spec, per process).

register_backend(tag, opener) → None

Register opener(spec) -> ArrayBackend under a spec tag.

release_backends(path) → int

Drop and close every cached backend that reads path. Returns how many.

spec_names_path(spec, path) → bool

Whether spec reaches path, nested views included.

Module Contents

class neu_vol.backends.base.ArrayBackend

Bases: Protocol

Minimal chunked-array interface the engine depends on.

read_region(region: Region) → numpy.ndarray

Read a rectangular region; returns an array of shape matching region.

to_spec() → dict[str, Any]

Return a JSON-serializable spec that open_backend() can reopen.

write_region(region: Region, data: numpy.ndarray) → None

Write data into region. data.shape must match the region.

property chunks: tuple[int, ...]

Storage chunk shape (the write granularity), same axis order as shape.

property dtype: numpy.dtype
property shape: tuple[int, ...]

Full array shape in canonical order ((c,) z, y, x).

neu_vol.backends.base.clear_backend_cache() → None

Drop all cached backends.

Call after anything that invalidates an open handle — deleting and recreating a volume at the same location, most importantly, where a cached handle would otherwise keep serving the old metadata.

neu_vol.backends.base.open_backend(spec: Mapping[str, Any]) → ArrayBackend

Open a backend from a serializable spec (cached per spec, per process).

spec["backend"] selects the implementation (e.g. "zarr3", "neuroglancer_precomputed", "image_stack", "hdf5").

The returned backend is shared: callers must treat it as a handle for region I/O and not mutate it. Use clear_backend_cache() if a volume is recreated underneath.

neu_vol.backends.base.register_backend(tag: str, opener: Any) → None

Register opener(spec) -> ArrayBackend under a spec tag.

neu_vol.backends.base.release_backends(path: str) → int

Drop and close every cached backend that reads path. Returns how many.

Call before rewriting a file in place. A cached HDF5Backend holds an open h5py.File, and HDF5 refuses to open a file for writing while any handle has it open read-only (file is already open for read-only); a surviving entry would also keep serving the pre-rewrite array. Closing, not just dropping, is what releases the lock deterministically. A backend with no close is simply dropped.

neu_vol.backends.base.spec_names_path(spec: Any, path: str) → bool

Whether spec reaches path, nested views included.

A view backend (crop, mask, remap) carries its source spec inside itself, so a match has to be looked for at any depth: a cached crop over an HDF5 file holds that file’s handle just as directly as the plain backend does.

neu_vol.backends.base.Region