Skip to content

zarr_indexing.messages

zarr_indexing.messages

The ndsel message layer — pure JSON in, canonical JSON out.

This module implements the ndsel draft wire format: a JSON-serializable representation of NumPy-style n-dimensional selections that adapts TensorStore's IndexTransform model. It is a pure JSON→JSON layer: it depends on nothing but the standard library, imposes no engine (numpy/array) constraints, and never rounds, clamps, or drops information. Engine constraints (finite bounds, in-memory IndexTransform construction) live one layer up, in json.py.

Two entry points:

  • parse_ndsel(obj) — structurally validate an ndsel message of any of the five kinds (point/box/slice/points/transform), returning it unchanged. Raises NdselError (carrying a spec reason code) on any defect.
  • normalize_ndsel(obj) — desugar and canonicalize a message to the single deterministic canonical transform body of the spec (section 4.3): a bare IndexTransform JSON body, without the kind discriminator. normalize is idempotent when its output is re-tagged with kind: "transform".

The canonical body is, field-for-field, a TensorStore IndexTransform (minus kind), so a normalized transform loads directly into TensorStore once kind is stripped.

Value rules enforced here: every integer is a 64-bit signed value; JSON booleans are not integers (Python's isinstance(True, int) is guarded against explicitly); the "-inf"/"+inf" sentinels are legal only in bound positions; an implicit bound is the one-element [n]-bracket form, and its implicit/explicit flag is preserved through normalization.

REASON_CODES module-attribute

REASON_CODES = frozenset(
    {
        "invalid_json",
        "unknown_kind",
        "unknown_field",
        "multiple_upper_bounds",
        "bounds_out_of_order",
        "output_map_conflict",
        "rank_mismatch",
        "step_zero",
        "negative_step_unsupported",
    }
)

__all__ module-attribute

__all__ = ['NdselError', 'normalize_ndsel', 'parse_ndsel']

NdselError

Bases: ValueError

An ndsel message failed validation.

Carries the spec reason code (one of REASON_CODES) so callers and the conformance harness can assert on it directly, plus a human-readable detail.

Examples:

>>> try:
...     normalize_ndsel({"kind": "bogus"})
... except NdselError as error:
...     (error.reason, str(error))
('unknown_kind', "unknown_kind: unknown kind 'bogus'")
Source code in src/zarr_indexing/messages.py
class NdselError(ValueError):
    """An ndsel message failed validation.

    Carries the spec `reason` code (one of `REASON_CODES`) so callers and the
    conformance harness can assert on it directly, plus a human-readable
    `detail`.

    Examples
    --------
    >>> try:
    ...     normalize_ndsel({"kind": "bogus"})
    ... except NdselError as error:
    ...     (error.reason, str(error))
    ('unknown_kind', "unknown_kind: unknown kind 'bogus'")
    """

    def __init__(self, reason: str, detail: str = "") -> None:
        """Store `reason` and `detail` and compose the message as `"reason: detail"`.

        `reason` is a spec reason code (one of `REASON_CODES`); `detail` is
        optional human-readable context, and when empty the message is the
        bare `reason`.
        """
        self.reason = reason
        self.detail = detail
        super().__init__(f"{reason}: {detail}" if detail else reason)

detail instance-attribute

detail = detail

reason instance-attribute

reason = reason

__init__

__init__(reason: str, detail: str = '') -> None

Store reason and detail and compose the message as "reason: detail".

reason is a spec reason code (one of REASON_CODES); detail is optional human-readable context, and when empty the message is the bare reason.

Source code in src/zarr_indexing/messages.py
def __init__(self, reason: str, detail: str = "") -> None:
    """Store `reason` and `detail` and compose the message as `"reason: detail"`.

    `reason` is a spec reason code (one of `REASON_CODES`); `detail` is
    optional human-readable context, and when empty the message is the
    bare `reason`.
    """
    self.reason = reason
    self.detail = detail
    super().__init__(f"{reason}: {detail}" if detail else reason)

normalize_ndsel

normalize_ndsel(obj: Any) -> dict[str, Any]

Desugar and canonicalize an ndsel message to its canonical transform body.

Accepts any of the five message kinds and returns the bare canonical IndexTransform body of spec section 4.3 — no kind field. Raises NdselError (carrying a reason code) for any invalid input.

Examples:

>>> body = normalize_ndsel({"kind": "box", "shape": [2, 3]})
>>> (body["input_rank"], body["input_inclusive_min"], body["input_exclusive_max"])
(2, [0, 0], [2, 3])
>>> body["output"][0]
{'offset': 0, 'stride': 1, 'input_dimension': 0}
Source code in src/zarr_indexing/messages.py
def normalize_ndsel(obj: Any) -> dict[str, Any]:
    """Desugar and canonicalize an ndsel message to its canonical transform body.

    Accepts any of the five message kinds and returns the bare canonical
    `IndexTransform` body of spec section 4.3 — no `kind` field. Raises
    `NdselError` (carrying a reason code) for any invalid input.

    Examples
    --------
    >>> body = normalize_ndsel({"kind": "box", "shape": [2, 3]})
    >>> (body["input_rank"], body["input_inclusive_min"], body["input_exclusive_max"])
    (2, [0, 0], [2, 3])
    >>> body["output"][0]
    {'offset': 0, 'stride': 1, 'input_dimension': 0}
    """
    message = _require_object(obj)
    kind = _message_kind(message)
    return _NORMALIZERS[kind](message)

parse_ndsel

parse_ndsel(obj: Any) -> dict[str, Any]

Structurally validate an ndsel message, returning it unchanged.

A lighter gate than normalize_ndsel: it confirms the message is a well-formed ndsel message of a recognized kind (correct field membership, JSON types, upper-bound exclusivity, domain ordering, step signs) and raises NdselError otherwise, but does not desugar it. Useful for validating a message you intend to keep in its compact shorthand form.

Examples:

>>> message = {"kind": "point", "coords": [3, 4]}
>>> parse_ndsel(message) is message
True
>>> normalize_ndsel(message)["output"]
[{'offset': 3}, {'offset': 4}]
Source code in src/zarr_indexing/messages.py
def parse_ndsel(obj: Any) -> dict[str, Any]:
    """Structurally validate an ndsel message, returning it unchanged.

    A lighter gate than `normalize_ndsel`: it confirms the message is a
    well-formed ndsel message of a recognized kind (correct field membership,
    JSON types, upper-bound exclusivity, domain ordering, step signs) and
    raises `NdselError` otherwise, but does not desugar it. Useful for
    validating a message you intend to keep in its compact shorthand form.

    Examples
    --------
    >>> message = {"kind": "point", "coords": [3, 4]}
    >>> parse_ndsel(message) is message
    True
    >>> normalize_ndsel(message)["output"]
    [{'offset': 3}, {'offset': 4}]
    """
    message = _require_object(obj)
    _message_kind(message)
    # Validation and desugaring share one pass; run it and discard the body.
    normalize_ndsel(message)
    return message