Skip to content

zarr_metadata.v2

zarr_metadata.v2

Zarr v2 metadata types.

zarr_metadata.v2.array

Zarr v2 array metadata types.

ZARR_V2_ARRAY_DIMENSION_SEPARATOR module-attribute

ZARR_V2_ARRAY_DIMENSION_SEPARATOR: Final = ('.', '/')

Tuple of permitted values for the dimension_separator field of v2 array metadata.

ZARR_V2_ARRAY_METADATA_STORE_KEY module-attribute

ZARR_V2_ARRAY_METADATA_STORE_KEY: Final[
    ZarrV2ArrayMetadataStoreKey
] = ".zarray"

The store key a v2 array's metadata document is persisted under.

ZARR_V2_ARRAY_ORDER module-attribute

ZARR_V2_ARRAY_ORDER: Final = ('C', 'F')

Tuple of permitted values for the order field of v2 array metadata.

ZarrV2ArrayDimensionSeparator module-attribute

ZarrV2ArrayDimensionSeparator = Literal['.', '/']

Literal type of permitted values for the dimension_separator field of v2 array metadata.

"." (legacy default) joins chunk grid coordinates as 0.0, 0.1, ... "/" joins them as 0/0, 0/1, ... yielding nested directories.

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

ZarrV2ArrayMetadataStoreKey module-attribute

ZarrV2ArrayMetadataStoreKey = Literal['.zarray']

Literal type of the store key holding a v2 array's metadata document.

ZarrV2ArrayOrder module-attribute

ZarrV2ArrayOrder = Literal['C', 'F']

Literal type of permitted values for the order field of v2 array metadata.

"C" (row-major) or "F" (column-major) — the in-chunk byte layout.

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

ZarrV2DataTypeMetadata module-attribute

ZarrV2DataTypeMetadata = TypeAliasType(
    "ZarrV2DataTypeMetadata",
    str
    | tuple[
        tuple[str, "ZarrV2DataTypeMetadata"]
        | tuple[
            str, "ZarrV2DataTypeMetadata", tuple[int, ...]
        ],
        ...,
    ],
)

The v2 dtype representation.

Either a numpy-style dtype string (e.g. "<f8", "|S10") or a tuple of field records describing a structured dtype. Each field record is either a 2-tuple (name, datatype) or a 3-tuple (name, datatype, shape) (the 3-tuple form indicates a subarray field). A field datatype may itself be another structured dtype.

Endianness is encoded in the prefix character of the dtype string; parsing it out is a caller concern, not part of this type.

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html#data-type-encoding

__all__ module-attribute

__all__ = [
    "ZARR_V2_ARRAY_DIMENSION_SEPARATOR",
    "ZARR_V2_ARRAY_METADATA_STORE_KEY",
    "ZARR_V2_ARRAY_ORDER",
    "ZarrV2ArrayDimensionSeparator",
    "ZarrV2ArrayMetadataJSON",
    "ZarrV2ArrayMetadataJSONPartial",
    "ZarrV2ArrayMetadataStoreKey",
    "ZarrV2ArrayOrder",
    "ZarrV2DataTypeMetadata",
    "ZarrV2ZArrayJSON",
]

ZarrV2ArrayMetadataJSON

Bases: TypedDict

Zarr v2 array metadata document, in-memory merged form.

Models the union of .zarray (the spec-defined fields, https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L51-L92) and .zattrs (user attributes, https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L323-L330). On disk, attributes live in a sibling .zattrs file and are not part of .zarray; this type folds them in as the attributes field so a single TypedDict represents the complete in-memory state of a v2 array node. Consumers that read or write a real .zarray file should split / merge attributes accordingly, or use ZarrV2ZArrayJSON (strict on-disk) plus ZarrV2ZAttrsJSON directly.

Open: other keys "SHOULD NOT be present ... and SHOULD be ignored by implementations" (https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L91-L92), and each other member is a JSON value.

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

Source code in src/zarr_metadata/v2/array.py
class ZarrV2ArrayMetadataJSON(TypedDict, extra_items=JSONValue):
    """
    Zarr v2 array metadata document, in-memory merged form.

    Models the union of `.zarray` (the spec-defined fields, https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L51-L92)
    and `.zattrs` (user attributes, https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L323-L330). On disk, attributes live in a sibling `.zattrs` file
    and are not part of `.zarray`; this type folds them in as the
    `attributes` field so a single TypedDict represents the complete
    in-memory state of a v2 array node. Consumers that read or write a
    real `.zarray` file should split / merge `attributes` accordingly,
    or use `ZarrV2ZArrayJSON` (strict on-disk) plus `ZarrV2ZAttrsJSON` directly.

    Open: other keys "SHOULD NOT be present ... and SHOULD be ignored by
    implementations" (https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L91-L92), and each
    other member is a JSON value.

    See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html
    """

    zarr_format: Literal[2]
    shape: tuple[int, ...]
    chunks: tuple[int, ...]
    dtype: ZarrV2DataTypeMetadata
    compressor: ZarrV2CodecMetadata | None
    fill_value: JSONValue
    order: ZarrV2ArrayOrder
    filters: tuple[ZarrV2CodecMetadata, ...] | None
    dimension_separator: NotRequired[ZarrV2ArrayDimensionSeparator]
    attributes: NotRequired[Mapping[str, JSONValue]]
    """User attributes from the sibling `.zattrs` file (not part of `.zarray`).

    See the class docstring for the rationale behind the merged representation.
    """

attributes instance-attribute

User attributes from the sibling .zattrs file (not part of .zarray).

See the class docstring for the rationale behind the merged representation.

chunks instance-attribute

chunks: tuple[int, ...]

compressor instance-attribute

compressor: ZarrV2CodecMetadata | None

dimension_separator instance-attribute

dtype instance-attribute

fill_value instance-attribute

fill_value: JSONValue

filters instance-attribute

filters: tuple[ZarrV2CodecMetadata, ...] | None

order instance-attribute

shape instance-attribute

shape: tuple[int, ...]

zarr_format instance-attribute

zarr_format: Literal[2]

ZarrV2ArrayMetadataJSONPartial

Bases: TypedDict

Partial form of ZarrV2ArrayMetadataJSON: every field is NotRequired.

Field annotations mirror ZarrV2ArrayMetadataJSON exactly. The only difference is total=False, which makes every key optional at the type level.

Use this when typing dicts that intentionally hold a subset of a complete v2 array metadata document — e.g. test fixtures that override only a few fields of a base template, or callers that build a fragment to be merged into a complete document elsewhere.

The NotRequired[...] wrappers on dimension_separator and attributes are intentional: keeping them preserves byte-identical __annotations__ with ZarrV2ArrayMetadataJSON so the == check in tests/test_partial_equivalence.py passes without special-casing those fields (PEP 655 explicitly permits NotRequired inside total=False).

Note: v2 array metadata has no extra_items setting: the v2 spec has no extension-field concept, and other .zarray keys "SHOULD be ignored by implementations" (https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L91-L92), so nothing beyond the spec-defined fields is modeled.

Drift between this type and ZarrV2ArrayMetadataJSON is prevented by tests/test_partial_equivalence.py.

Source code in src/zarr_metadata/v2/array.py
class ZarrV2ArrayMetadataJSONPartial(TypedDict, total=False, extra_items=JSONValue):
    """
    Partial form of `ZarrV2ArrayMetadataJSON`: every field is `NotRequired`.

    Field annotations mirror `ZarrV2ArrayMetadataJSON` exactly. The only difference is
    `total=False`, which makes every key optional at the type level.

    Use this when typing dicts that intentionally hold a subset of a complete
    v2 array metadata document — e.g. test fixtures that override only a few
    fields of a base template, or callers that build a fragment to be merged
    into a complete document elsewhere.

    The `NotRequired[...]` wrappers on `dimension_separator` and `attributes`
    are intentional: keeping them preserves byte-identical `__annotations__`
    with `ZarrV2ArrayMetadataJSON` so the `==` check in
    `tests/test_partial_equivalence.py` passes without special-casing those
    fields (PEP 655 explicitly permits `NotRequired` inside `total=False`).

    Note: v2 array metadata has no `extra_items` setting: the v2 spec has no
    extension-field concept, and other `.zarray` keys "SHOULD be ignored by
    implementations" (https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L91-L92), so nothing beyond the spec-defined
    fields is modeled.

    Drift between this type and `ZarrV2ArrayMetadataJSON` is prevented by
    `tests/test_partial_equivalence.py`.
    """

    zarr_format: Literal[2]
    shape: tuple[int, ...]
    chunks: tuple[int, ...]
    dtype: ZarrV2DataTypeMetadata
    compressor: ZarrV2CodecMetadata | None
    fill_value: JSONValue
    order: ZarrV2ArrayOrder
    filters: tuple[ZarrV2CodecMetadata, ...] | None
    dimension_separator: NotRequired[ZarrV2ArrayDimensionSeparator]
    attributes: NotRequired[Mapping[str, JSONValue]]
    """User attributes from the sibling `.zattrs` file (not part of `.zarray`).

    See the class docstring for the rationale behind the merged representation.
    """

attributes instance-attribute

User attributes from the sibling .zattrs file (not part of .zarray).

See the class docstring for the rationale behind the merged representation.

chunks instance-attribute

chunks: tuple[int, ...]

compressor instance-attribute

compressor: ZarrV2CodecMetadata | None

dimension_separator instance-attribute

dtype instance-attribute

fill_value instance-attribute

fill_value: JSONValue

filters instance-attribute

filters: tuple[ZarrV2CodecMetadata, ...] | None

order instance-attribute

shape instance-attribute

shape: tuple[int, ...]

zarr_format instance-attribute

zarr_format: Literal[2]

ZarrV2ZArrayJSON

Bases: TypedDict

On-disk .zarray file content.

Strict shape of the JSON document persisted at <path>/.zarray for a v2 array. User attributes live in a sibling .zattrs file and are NOT part of this type; see ZarrV2ZAttrsJSON.

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

Source code in src/zarr_metadata/v2/array.py
class ZarrV2ZArrayJSON(TypedDict):
    """
    On-disk `.zarray` file content.

    Strict shape of the JSON document persisted at `<path>/.zarray` for
    a v2 array. User attributes live in a sibling `.zattrs` file and are
    NOT part of this type; see `ZarrV2ZAttrsJSON`.

    See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html
    """

    zarr_format: Literal[2]
    shape: tuple[int, ...]
    chunks: tuple[int, ...]
    dtype: ZarrV2DataTypeMetadata
    compressor: ZarrV2CodecMetadata | None
    fill_value: JSONValue
    order: ZarrV2ArrayOrder
    filters: tuple[ZarrV2CodecMetadata, ...] | None
    dimension_separator: NotRequired[ZarrV2ArrayDimensionSeparator]

chunks instance-attribute

chunks: tuple[int, ...]

compressor instance-attribute

compressor: ZarrV2CodecMetadata | None

dimension_separator instance-attribute

dtype instance-attribute

fill_value instance-attribute

fill_value: JSONValue

filters instance-attribute

filters: tuple[ZarrV2CodecMetadata, ...] | None

order instance-attribute

shape instance-attribute

shape: tuple[int, ...]

zarr_format instance-attribute

zarr_format: Literal[2]

zarr_metadata.v2.group

Zarr v2 group metadata types.

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

ZARR_V2_GROUP_METADATA_STORE_KEY module-attribute

ZARR_V2_GROUP_METADATA_STORE_KEY: Final[
    ZarrV2GroupMetadataStoreKey
] = ".zgroup"

The store key a v2 group's metadata document is persisted under.

ZarrV2GroupMetadataStoreKey module-attribute

ZarrV2GroupMetadataStoreKey = Literal['.zgroup']

Literal type of the store key holding a v2 group's metadata document.

__all__ module-attribute

__all__ = [
    "ZARR_V2_GROUP_METADATA_STORE_KEY",
    "ZarrV2GroupMetadataJSON",
    "ZarrV2GroupMetadataJSONPartial",
    "ZarrV2GroupMetadataStoreKey",
    "ZarrV2ZGroupJSON",
]

ZarrV2GroupMetadataJSON

Bases: TypedDict

Zarr v2 group metadata document, in-memory merged form.

Models the union of .zgroup (the spec-defined zarr_format field, https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L306-L313) and .zattrs (user attributes, https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L323-L330). On disk these are persisted as two separate files; this type folds them so a single TypedDict represents the complete in-memory state of a v2 group node. Consumers that read or write the real on-disk files should use ZarrV2ZGroupJSON (strict .zgroup) plus ZarrV2ZAttrsJSON directly.

Closed: .zgroup holds no other keys ("Other keys MUST NOT be present", https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L313), and attributes is the one member folded in.

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

Source code in src/zarr_metadata/v2/group.py
class ZarrV2GroupMetadataJSON(TypedDict, closed=True):
    """
    Zarr v2 group metadata document, in-memory merged form.

    Models the union of `.zgroup` (the spec-defined `zarr_format` field,
    https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L306-L313) and `.zattrs` (user attributes, https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L323-L330). On disk these are persisted as two
    separate files; this type folds them so a single TypedDict represents
    the complete in-memory state of a v2 group node. Consumers that read
    or write the real on-disk files should use `ZarrV2ZGroupJSON` (strict
    `.zgroup`) plus `ZarrV2ZAttrsJSON` directly.

    Closed: `.zgroup` holds no other keys ("Other keys MUST NOT be present",
    https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L313),
    and `attributes` is the one member folded in.

    See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html
    """

    zarr_format: Literal[2]
    attributes: NotRequired[Mapping[str, JSONValue]]

attributes instance-attribute

zarr_format instance-attribute

zarr_format: Literal[2]

ZarrV2GroupMetadataJSONPartial

Bases: TypedDict

Partial form of ZarrV2GroupMetadataJSON: every field is NotRequired.

Field annotations mirror ZarrV2GroupMetadataJSON exactly. The only difference is total=False, which makes every key optional at the type level.

Use this when typing dicts that intentionally hold a subset of a complete v2 group metadata document — e.g. test fixtures that override only a few fields of a base template, or callers that build a fragment to be merged into a complete document elsewhere. Provided for symmetry with the other *Partial types; the practical effect is that zarr_format becomes optional.

The NotRequired[...] wrapper on attributes is intentional: keeping it preserves byte-identical __annotations__ with ZarrV2GroupMetadataJSON so the == check in tests/test_partial_equivalence.py passes without special-casing that field (PEP 655 explicitly permits NotRequired inside total=False).

Note: v2 group metadata is closed (the v2 spec has no extension-field concept, and .zgroup forbids other keys outright: https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L313), and so is this partial.

Drift between this type and ZarrV2GroupMetadataJSON is prevented by tests/test_partial_equivalence.py.

Source code in src/zarr_metadata/v2/group.py
class ZarrV2GroupMetadataJSONPartial(TypedDict, total=False, closed=True):
    """
    Partial form of `ZarrV2GroupMetadataJSON`: every field is `NotRequired`.

    Field annotations mirror `ZarrV2GroupMetadataJSON` exactly. The only difference is
    `total=False`, which makes every key optional at the type level.

    Use this when typing dicts that intentionally hold a subset of a complete
    v2 group metadata document — e.g. test fixtures that override only a few
    fields of a base template, or callers that build a fragment to be merged
    into a complete document elsewhere. Provided for symmetry with the other
    `*Partial` types; the practical effect is that `zarr_format` becomes optional.

    The `NotRequired[...]` wrapper on `attributes` is intentional: keeping it
    preserves byte-identical `__annotations__` with `ZarrV2GroupMetadataJSON` so the
    `==` check in `tests/test_partial_equivalence.py` passes without
    special-casing that field (PEP 655 explicitly permits `NotRequired` inside
    `total=False`).

    Note: v2 group metadata is closed (the v2 spec has no extension-field
    concept, and `.zgroup` forbids other keys outright:
    https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L313), and so is this partial.

    Drift between this type and `ZarrV2GroupMetadataJSON` is prevented by
    `tests/test_partial_equivalence.py`.
    """

    zarr_format: Literal[2]
    attributes: NotRequired[Mapping[str, JSONValue]]

attributes instance-attribute

zarr_format instance-attribute

zarr_format: Literal[2]

ZarrV2ZGroupJSON

Bases: TypedDict

On-disk .zgroup file content.

Strict shape of the JSON document persisted at <path>/.zgroup for a v2 group. The spec defines exactly one field and forbids others. User attributes live in a sibling .zattrs file and are NOT part of this type; see ZarrV2ZAttrsJSON. https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L306-L313

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

Source code in src/zarr_metadata/v2/group.py
class ZarrV2ZGroupJSON(TypedDict, closed=True):
    """
    On-disk `.zgroup` file content.

    Strict shape of the JSON document persisted at `<path>/.zgroup` for
    a v2 group. The spec defines exactly one field and forbids others. User
    attributes live in a sibling `.zattrs` file and are NOT part of this
    type; see `ZarrV2ZAttrsJSON`.
      https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L306-L313

    See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html
    """

    zarr_format: Literal[2]

zarr_format instance-attribute

zarr_format: Literal[2]

zarr_metadata.v2.attributes

Zarr v2 user-attributes file content.

See https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

ZARR_V2_ATTRIBUTES_STORE_KEY module-attribute

ZARR_V2_ATTRIBUTES_STORE_KEY: Final[
    ZarrV2AttributesStoreKey
] = ".zattrs"

The store key a v2 node's user attributes are persisted under.

Shared by arrays and groups: both node types keep their attributes in a sibling .zattrs file.

ZarrV2AttributesStoreKey module-attribute

ZarrV2AttributesStoreKey = Literal['.zattrs']

Literal type of the store key holding a v2 node's user attributes.

ZarrV2ZAttrsJSON module-attribute

ZarrV2ZAttrsJSON = Mapping[str, JSONValue]

On-disk .zattrs file content.

A JSON object holding user-defined attributes for a v2 array or group. Spec-defined keys for arrays / groups live in sibling .zarray / .zgroup files (modeled by ZarrV2ZArrayJSON / ZarrV2ZGroupJSON). This type does not constrain the keys or values of the attributes mapping. https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L323-L330

__all__ module-attribute

__all__ = [
    "ZARR_V2_ATTRIBUTES_STORE_KEY",
    "ZarrV2AttributesStoreKey",
    "ZarrV2ZAttrsJSON",
]

zarr_metadata.v2.codec

Zarr v2 codecs: the configuration shape, and one definition per numcodecs id this package models.

In v2, compressors and filters are numcodecs configuration dicts: a required id field naming the codec, plus codec-specific parameters.

ADLER32_V2 module-attribute

ADLER32_V2: Final = ZarrV2CodecDefinition(
    name="adler32", configuration=ZarrV2Checksum32Parameters
)

numcodecs.Adler32.

ASTYPE_V2 module-attribute

ASTYPE_V2: Final = ZarrV2CodecDefinition(
    name="astype",
    configuration=ZarrV2AsTypeParameters,
    rules=dtype_parameter("encode_dtype", "decode_dtype"),
)

numcodecs.AsType.

BITROUND_V2 module-attribute

BITROUND_V2: Final = ZarrV2CodecDefinition(
    name="bitround", configuration=ZarrV2BitRoundParameters
)

numcodecs.BitRound.

BLOSC_V2 module-attribute

BLOSC_V2: Final = ZarrV2CodecDefinition(
    name="blosc", configuration=ZarrV2BloscParameters
)

numcodecs.Blosc.

BZ2_V2 module-attribute

BZ2_V2: Final = ZarrV2CodecDefinition(
    name="bz2", configuration=ZarrV2Bz2Parameters
)

numcodecs.BZ2.

CRC32C_V2 module-attribute

CRC32C_V2: Final = ZarrV2CodecDefinition(
    name="crc32c", configuration=ZarrV2Checksum32Parameters
)

numcodecs.CRC32C.

CRC32_V2 module-attribute

CRC32_V2: Final = ZarrV2CodecDefinition(
    name="crc32", configuration=ZarrV2Checksum32Parameters
)

numcodecs.CRC32.

DELTA_V2 module-attribute

DELTA_V2: Final = ZarrV2CodecDefinition(
    name="delta",
    configuration=ZarrV2DeltaParameters,
    rules=dtype_parameter("dtype", "astype"),
)

numcodecs.Delta.

FIXEDSCALEOFFSET_V2 module-attribute

FIXEDSCALEOFFSET_V2: Final = ZarrV2CodecDefinition(
    name="fixedscaleoffset",
    configuration=ZarrV2FixedScaleOffsetParameters,
    rules=dtype_parameter("dtype", "astype"),
)

numcodecs.FixedScaleOffset.

FLETCHER32_V2 module-attribute

FLETCHER32_V2: Final = ZarrV2CodecDefinition(
    name="fletcher32", configuration=EmptyConfiguration
)

numcodecs.Fletcher32: nothing to configure.

GZIP_V2 module-attribute

GZIP_V2: Final = ZarrV2CodecDefinition(
    name="gzip", configuration=ZarrV2GzipParameters
)

numcodecs.GZip.

LZ4_V2 module-attribute

LZ4_V2: Final = ZarrV2CodecDefinition(
    name="lz4", configuration=ZarrV2Lz4Parameters
)

numcodecs.LZ4.

LZMA_V2 module-attribute

LZMA_V2: Final = ZarrV2CodecDefinition(
    name="lzma", configuration=ZarrV2LzmaParameters
)

numcodecs.LZMA.

PACKBITS_V2 module-attribute

PACKBITS_V2: Final = ZarrV2CodecDefinition(
    name="packbits", configuration=EmptyConfiguration
)

numcodecs.PackBits: nothing to configure.

QUANTIZE_V2 module-attribute

QUANTIZE_V2: Final = ZarrV2CodecDefinition(
    name="quantize",
    configuration=ZarrV2QuantizeParameters,
    rules=dtype_parameter(
        "dtype", "astype", float_only=True
    ),
)

numcodecs.Quantize.

SHUFFLE_V2 module-attribute

SHUFFLE_V2: Final = ZarrV2CodecDefinition(
    name="shuffle", configuration=ZarrV2ShuffleParameters
)

numcodecs.Shuffle.

V2_CODECS module-attribute

Every codec numcodecs 0.16 configures that this package models.

VLEN_ARRAY_V2 module-attribute

VLEN_ARRAY_V2: Final = ZarrV2CodecDefinition(
    name="vlen-array",
    configuration=ZarrV2VLenArrayParameters,
    rules=dtype_parameter("dtype"),
)

numcodecs.VLenArray.

VLEN_BYTES_V2 module-attribute

VLEN_BYTES_V2: Final = ZarrV2CodecDefinition(
    name="vlen-bytes", configuration=EmptyConfiguration
)

numcodecs.VLenBytes: nothing to configure.

VLEN_UTF8_V2 module-attribute

VLEN_UTF8_V2: Final = ZarrV2CodecDefinition(
    name="vlen-utf8", configuration=EmptyConfiguration
)

numcodecs.VLenUTF8: nothing to configure.

ZLIB_V2 module-attribute

ZLIB_V2: Final = ZarrV2CodecDefinition(
    name="zlib", configuration=ZarrV2ZlibParameters
)

numcodecs.Zlib.

ZSTD_V2 module-attribute

ZSTD_V2: Final = ZarrV2CodecDefinition(
    name="zstd", configuration=ZarrV2ZstdParameters
)

numcodecs.Zstd.

__all__ module-attribute

__all__ = [
    "ADLER32_V2",
    "ASTYPE_V2",
    "BITROUND_V2",
    "BLOSC_V2",
    "BZ2_V2",
    "CRC32C_V2",
    "CRC32_V2",
    "DELTA_V2",
    "FIXEDSCALEOFFSET_V2",
    "FLETCHER32_V2",
    "GZIP_V2",
    "LZ4_V2",
    "LZMA_V2",
    "PACKBITS_V2",
    "QUANTIZE_V2",
    "SHUFFLE_V2",
    "V2_CODECS",
    "VLEN_ARRAY_V2",
    "VLEN_BYTES_V2",
    "VLEN_UTF8_V2",
    "ZLIB_V2",
    "ZSTD_V2",
    "ZarrV2CodecMetadata",
]

ZarrV2CodecMetadata

Bases: TypedDict

A numcodecs configuration dict, used as a v2 compressor or filter.

The required id field names the codec; codec-specific parameters (e.g. cname, clevel for blosc) appear as extra fields.

See the "compressor" and "filters" sections of https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html

Source code in src/zarr_metadata/v2/_codec_json.py
class ZarrV2CodecMetadata(TypedDict, extra_items=JSONValue):
    """
    A numcodecs configuration dict, used as a v2 compressor or filter.

    The required `id` field names the codec; codec-specific parameters
    (e.g. `cname`, `clevel` for blosc) appear as extra fields.

    See the "compressor" and "filters" sections of
    https://zarr-specs.readthedocs.io/en/latest/v2/v2.0.html
    """

    id: str

id instance-attribute

id: str

zarr_metadata.v2.consolidated

Zarr v2 consolidated metadata (.zmetadata file).

This module models the de-facto .zmetadata file used by the reference Python implementation of Zarr v2. This is NOT a spec artifact. There is no Zarr v2 specification that defines .zmetadata; it is a canonical-implementation convention.

ZARR_V2_CONSOLIDATED_METADATA_STORE_KEY module-attribute

ZARR_V2_CONSOLIDATED_METADATA_STORE_KEY: Final[
    ZarrV2ConsolidatedMetadataStoreKey
] = ".zmetadata"

The store key a v2 hierarchy's consolidated metadata is persisted under.

Like the document it names, this is a reference-implementation convention rather than a spec artifact; see the module docstring.

ZarrV2ConsolidatedMetadataStoreKey module-attribute

ZarrV2ConsolidatedMetadataStoreKey = Literal['.zmetadata']

Literal type of the store key holding a v2 hierarchy's consolidated metadata.

__all__ module-attribute

__all__ = [
    "ZARR_V2_CONSOLIDATED_METADATA_STORE_KEY",
    "ZarrV2ConsolidatedMetadataJSON",
    "ZarrV2ConsolidatedMetadataStoreKey",
]

ZarrV2ConsolidatedMetadataJSON

Bases: TypedDict

.zmetadata file contents.

The metadata map uses flat path keys ("foo/bar/.zarray", "foo/.zattrs", etc.) pointing to the JSON contents of the file at that path. The keys include the filename suffix, not just the node path; the value's shape is determined by which file the key points at:

  • <path>/.zarray -> ZarrV2ZArrayJSON
  • <path>/.zgroup -> ZarrV2ZGroupJSON
  • <path>/.zattrs -> ZarrV2ZAttrsJSON

The TypedDict cannot discriminate the value shape on the key suffix at the type level; consumers should narrow at runtime by inspecting key.endswith(".zarray") etc.

Source code in src/zarr_metadata/v2/consolidated.py
class ZarrV2ConsolidatedMetadataJSON(TypedDict):
    """
    `.zmetadata` file contents.

    The `metadata` map uses flat path keys (`"foo/bar/.zarray"`,
    `"foo/.zattrs"`, etc.) pointing to the JSON contents of the file at
    that path. The keys include the filename suffix, not just the node
    path; the value's shape is determined by which file the key points at:

    - `<path>/.zarray` -> `ZarrV2ZArrayJSON`
    - `<path>/.zgroup` -> `ZarrV2ZGroupJSON`
    - `<path>/.zattrs` -> `ZarrV2ZAttrsJSON`

    The TypedDict cannot discriminate the value shape on the key suffix
    at the type level; consumers should narrow at runtime by inspecting
    `key.endswith(".zarray")` etc.
    """

    zarr_consolidated_format: Literal[1]
    metadata: Mapping[str, ZarrV2ZArrayJSON | ZarrV2ZGroupJSON | ZarrV2ZAttrsJSON]

metadata instance-attribute

zarr_consolidated_format instance-attribute

zarr_consolidated_format: Literal[1]

zarr_metadata.v2.definition

Zarr v2 fields read against their definitions: the public door.

A v2 array document has two kinds of field: its dtype, and the codecs in compressor and filters. Zarr v2 has no extension registry, but it has a scope all the same: the data types zarr-python 2.x writes, one definition per NumPy family, and the codecs numcodecs 0.16 configures, one per id this package models. CORE_V2 is that scope. Read one field in it with resolve_dtype_v2 or resolve_codec_v2, which give AcceptedField, UnclaimedField or RefusedField as zarr_metadata.v3.definition.resolve does for a v3 field; the scope algebra -- Context.of, extended_with, joined, claimant -- is the same Context.

A dtype reads as its family, the typestr's byte order, size and unit its configuration: <f4 is float with {"byteorder": "<", "itemsize": 4}, and its simplest spelling is the typestr again. A records array reads as struct, each record's type a nested field. A codec reads by its id, its other members the parameters. A typestr of a type code the spec does not list, or a codec id the package does not model, is UnclaimedField.

CORE_V2 module-attribute

The data types zarr-python 2.x writes and the codecs numcodecs 0.16 configures.

ClaimKey module-attribute

A kind and the name a definition is filed under: what a scope answers claimant for.

Claims module-attribute

Claims: TypeAlias = Mapping[
    ClaimKey, Definition[Any] | None
]

What a reading claims of each name a document writes: the definition that read it, or None where nothing claimed it.

ResolvedField module-attribute

ResolvedField = TypeAliasType(
    "ResolvedField",
    "AcceptedField[D] | UnclaimedField | RefusedField[D]",
    type_params=(D,),
)

One metadata field as a scope read it: read by the definition that claims its name, claimed by nothing, or refused.

V2_CODECS module-attribute

Every codec numcodecs 0.16 configures that this package models.

V2_DATA_TYPES module-attribute

Every v2 data type, by family.

ZarrV2DataTypeField module-attribute

ZarrV2DataTypeField = TypeAliasType(
    "ZarrV2DataTypeField", ZarrV2DataTypeMetadata
)

A member holding a v2 dtype: a document's dtype, or a struct record's type; read in the scope what holds it is read in.

AcceptedField dataclass

Bases: Generic[D]

A field a definition in scope read: the name it is written with, the definition, and the configuration it allowed.

A problem with the envelope around it -- a stray member, a must_understand of false -- is reported with the field and leaves it read; so is a problem of a field its configuration holds, which is that field's own, as nested says. Two fields are equal when they read the same, however each was spelled, as field_key compares them: "bytes" and {"name": "bytes"} are one field, and so are a blosc with and without the typesize that noshuffle ignores, which the definition's canonical folds. Equal fields hash alike.

Source code in src/zarr_metadata/v3/_definition.py
@dataclass(frozen=True, slots=True, kw_only=True)
class AcceptedField(Generic[D]):
    """A field a definition in scope read: the name it is written with, the definition, and the configuration it allowed.

    A problem with the envelope around it -- a stray member, a
    `must_understand` of `false` -- is reported with the field and leaves
    it read; so is a problem of a field its configuration holds, which is
    that field's own, as `nested` says. Two fields are equal when they
    read the same, however each was spelled, as `field_key` compares
    them: `"bytes"` and `{"name": "bytes"}` are one field, and so are a
    blosc with and without the `typesize` that `noshuffle` ignores, which
    the definition's `canonical` folds. Equal fields hash alike.
    """

    json: JSONValue
    """The field as written, refined: arrays as tuples; it takes no part in equality."""
    name: str
    """The name it is written with: `"r16"`, though its definition is filed under `r*`."""
    definition: D
    """The definition that read it."""
    configuration: Mapping[str, JSONValue]
    """The configuration, type-checked and allowed by the rules; for raw bits, what the name carries.

    Each field it holds is written as a document writes it, as that
    field's `to_json` writes it, so the configuration says what was read
    however it was spelled: a shard's `"crc32c"` and `{"name": "crc32c"}`
    are one index codec.
    """
    nested: Nested = dataclasses.field(default_factory=_nothing_nested)
    """The fields the configuration holds, each as the scope read it, by where it sits in the configuration.

    A struct's field types at `("fields", 0, "data_type")`, a shard's
    codecs at `("codecs", 0)`: what a definition's functions consult about
    the fields inside its own.
    """
    read_as: type[Definition[Any]] = dataclasses.field(init=False, repr=False)
    """The kind of metadata it was read as: its definition's."""

    def __eq__(self, other: object) -> bool:
        if not is_field(other):
            return NotImplemented
        return field_key(self) == field_key(other)

    def __hash__(self) -> int:
        return hash(field_key(self))

    def __post_init__(self) -> None:
        # The runtime half of the annotations: a field read by hand, as an
        # extension's may be, fails here rather than where a function trusts it.
        definition = cast("object", self.definition)
        kind = kind_of(cast("Definition[Any]", definition))
        refusal = (
            f"a field read is read by a definition of a kind, got {definition!r}"
            if kind is None
            else _misread(definition, kind, self.name)
        )
        if refusal is not None:
            raise TypeError(refusal)
        object.__setattr__(self, "read_as", kind)

    def to_json(self) -> JSONValue:
        """The field as a document writes it, for every reader: its configuration as read, sharing nothing with the field.

        The envelope takes the fewest words every reader takes: a data type
        with nothing to configure is its bare name, as core data types have
        been written since Zarr v3.0; any other field is an object,
        `{"name": ...}`, since a Zarr v3.0 reader takes no bare name in
        `codecs`
        (https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/core/index.rst#L585-L592).
        A name that carries its configuration, as raw bits' does, is
        written alone.
        """
        return copied(written_json(self))

configuration instance-attribute

configuration: Mapping[str, JSONValue]

The configuration, type-checked and allowed by the rules; for raw bits, what the name carries.

Each field it holds is written as a document writes it, as that field's to_json writes it, so the configuration says what was read however it was spelled: a shard's "crc32c" and {"name": "crc32c"} are one index codec.

definition instance-attribute

definition: D

The definition that read it.

json instance-attribute

json: JSONValue

The field as written, refined: arrays as tuples; it takes no part in equality.

name instance-attribute

name: str

The name it is written with: "r16", though its definition is filed under r*.

nested class-attribute instance-attribute

nested: Nested = dataclasses.field(
    default_factory=_nothing_nested
)

The fields the configuration holds, each as the scope read it, by where it sits in the configuration.

A struct's field types at ("fields", 0, "data_type"), a shard's codecs at ("codecs", 0): what a definition's functions consult about the fields inside its own.

read_as class-attribute instance-attribute

read_as: type[Definition[Any]] = dataclasses.field(
    init=False, repr=False
)

The kind of metadata it was read as: its definition's.

to_json

to_json() -> JSONValue

The field as a document writes it, for every reader: its configuration as read, sharing nothing with the field.

The envelope takes the fewest words every reader takes: a data type with nothing to configure is its bare name, as core data types have been written since Zarr v3.0; any other field is an object, {"name": ...}, since a Zarr v3.0 reader takes no bare name in codecs (https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/core/index.rst#L585-L592). A name that carries its configuration, as raw bits' does, is written alone.

Source code in src/zarr_metadata/v3/_definition.py
def to_json(self) -> JSONValue:
    """The field as a document writes it, for every reader: its configuration as read, sharing nothing with the field.

    The envelope takes the fewest words every reader takes: a data type
    with nothing to configure is its bare name, as core data types have
    been written since Zarr v3.0; any other field is an object,
    `{"name": ...}`, since a Zarr v3.0 reader takes no bare name in
    `codecs`
    (https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/core/index.rst#L585-L592).
    A name that carries its configuration, as raw bits' does, is
    written alone.
    """
    return copied(written_json(self))

Conflict dataclass

One place two readings of a name disagree: the key, what one claimed, what the other found, and where in a document when known.

Source code in src/zarr_metadata/v3/_scope.py
@dataclass(frozen=True, slots=True)
class Conflict:
    """One place two readings of a name disagree: the key, what one claimed, what the other found, and where in a document when known."""

    key: ClaimKey
    claimed: Definition[Any] | None
    found: Definition[Any] | None
    loc: Loc | None = None

    def __str__(self) -> str:
        kind, name = self.key
        where = "" if self.loc is None else f" at {self.loc!r}"
        return f"{kind_name(kind)} {name!r}{where}: claimed {self.claimed!r}, found {self.found!r}"

Context dataclass

The definitions in scope while metadata is read.

A value with no reading of its own: resolve reads a field in it, and claimant is the one question it answers, which definition a name belongs to. Built from definitions with Context.of, extended with more by extended_with; two scopes are equal when they file the same definitions, and equal scopes hash alike.

Source code in src/zarr_metadata/v3/_registry.py
@dataclass(frozen=True, slots=True, eq=False)
class Context:
    """The definitions in scope while metadata is read.

    A value with no reading of its own: `resolve` reads a field in it,
    and `claimant` is the one question it answers, which definition a
    name belongs to. Built from definitions with `Context.of`, extended
    with more by `extended_with`; two scopes are equal when they file the
    same definitions, and equal scopes hash alike.
    """

    tables: Tables

    @classmethod
    def of(cls, *definitions: Definition[Any]) -> Context:
        """A scope of exactly these definitions; a later one takes a name over from an earlier.

        `TypeError` for a definition of no kind, which no position in a
        document could hold.
        """
        tables: dict[type[Definition[Any]], dict[str, Definition[Any]]] = {}
        for definition in definitions:
            kind = kind_of(definition)
            if kind is None:
                msg = (
                    f"{definition.name!r} is a definition of no kind; build it as a "
                    "CodecDefinition, DataTypeDefinition, ChunkGridDefinition, "
                    "ChunkKeyEncodingDefinition or StorageTransformerDefinition, or as a "
                    "kind of your own"
                )
                raise TypeError(msg)
            tables.setdefault(kind, {})[definition.name] = definition
        return cls(
            MappingProxyType({kind: MappingProxyType(table) for kind, table in tables.items()})
        )

    def extended_with(self, *definitions: Definition[Any]) -> Context:
        """This scope, plus definitions of your own.

        A name already filed under the same kind is taken over by what is
        passed here, which is how a reader substitutes its own reading of a
        codec the package already defines -- or of raw bits, by defining
        `r*`.
        """
        return Context.of(*self.definitions(), *definitions)

    def definitions(self) -> tuple[Definition[Any], ...]:
        """Every definition in scope, kind by kind."""
        return tuple(entry for table in self.tables.values() for entry in table.values())

    def __repr__(self) -> str:
        # Short, as a default argument shows it: in full, a scope's repr is
        # every definition's, and `help` of a validator runs to pages.
        return f"Context(<{len(self.definitions())} definitions>)"

    def __reduce__(self) -> tuple[Callable[..., Context], tuple[Definition[Any], ...]]:
        # A scope is its definitions, so it pickles as them, and goes to
        # another process with the documents it is to read there.
        return (Context.of, self.definitions())

    def __copy__(self) -> Context:
        return self

    def __deepcopy__(self, memo: dict[int, object]) -> Context:
        # A scope never changes, so a copy of it is itself.
        return self

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Context):
            return NotImplemented
        return self._filed() == other._filed()

    def __hash__(self) -> int:
        return hash(self._filed())

    def _filed(self) -> frozenset[tuple[type[Definition[Any]], str, Definition[Any]]]:
        """Every definition in scope with the kind and name it is filed under: what two scopes are compared by."""
        return frozenset(
            (kind, name, definition)
            for kind, table in self.tables.items()
            for name, definition in table.items()
        )

    def disagreements(self, claims: Claims) -> Disagreements:
        """Where this scope reads `claims`, a reading's, otherwise: what it would gain, and what it conflicts with, as `Disagreements` says.

        A claim is keyed by the name its definition is filed under -- raw
        bits under `r*` -- so it is looked up as filed, not as a document
        writes it.
        """
        return disagreements_of(lambda kind, name: self.tables.get(kind, {}).get(name), claims)

    @classmethod
    def joined(cls, *contexts: Context) -> Context:
        """The least scope that files everything each of `contexts` files: their join.

        `ScopeConflictError` when two of them file different definitions
        under one name of one kind; `extended_with` is for taking a name
        over on purpose.
        """
        filed: dict[tuple[type[Definition[Any]], str], Definition[Any]] = {}
        conflicts: list[Conflict] = []
        for context in contexts:
            for kind, table in context.tables.items():
                for name, definition in table.items():
                    held = filed.get((kind, name))
                    if held is not None and held != definition:
                        conflicts.append(Conflict((kind, name), held, definition))
                        continue
                    filed[kind, name] = definition
        if len(conflicts) != 0:
            raise ScopeConflictError(conflicts)
        return cls.of(*filed.values())

    def claimant(self, kind: type[D], name: str) -> D | None:
        """The definition of `kind` in scope that reads `name`, a name a document writes; None if none does.

        The one filed under the name `spelled` reads it as: itself, but
        for raw bits, `r16` read by the definition of `r*`.
        """
        asked = as_kind(kind)
        filed, _ = spelled(asked, name)
        if filed is None:
            return None
        return cast("D | None", self.tables.get(asked, {}).get(filed))

claimant

claimant(kind: type[D], name: str) -> D | None

The definition of kind in scope that reads name, a name a document writes; None if none does.

The one filed under the name spelled reads it as: itself, but for raw bits, r16 read by the definition of r*.

Source code in src/zarr_metadata/v3/_registry.py
def claimant(self, kind: type[D], name: str) -> D | None:
    """The definition of `kind` in scope that reads `name`, a name a document writes; None if none does.

    The one filed under the name `spelled` reads it as: itself, but
    for raw bits, `r16` read by the definition of `r*`.
    """
    asked = as_kind(kind)
    filed, _ = spelled(asked, name)
    if filed is None:
        return None
    return cast("D | None", self.tables.get(asked, {}).get(filed))

definitions

definitions() -> tuple[Definition[Any], ...]

Every definition in scope, kind by kind.

Source code in src/zarr_metadata/v3/_registry.py
def definitions(self) -> tuple[Definition[Any], ...]:
    """Every definition in scope, kind by kind."""
    return tuple(entry for table in self.tables.values() for entry in table.values())

disagreements

disagreements(claims: Claims) -> Disagreements

Where this scope reads claims, a reading's, otherwise: what it would gain, and what it conflicts with, as Disagreements says.

A claim is keyed by the name its definition is filed under -- raw bits under r* -- so it is looked up as filed, not as a document writes it.

Source code in src/zarr_metadata/v3/_registry.py
def disagreements(self, claims: Claims) -> Disagreements:
    """Where this scope reads `claims`, a reading's, otherwise: what it would gain, and what it conflicts with, as `Disagreements` says.

    A claim is keyed by the name its definition is filed under -- raw
    bits under `r*` -- so it is looked up as filed, not as a document
    writes it.
    """
    return disagreements_of(lambda kind, name: self.tables.get(kind, {}).get(name), claims)

extended_with

extended_with(*definitions: Definition[Any]) -> Context

This scope, plus definitions of your own.

A name already filed under the same kind is taken over by what is passed here, which is how a reader substitutes its own reading of a codec the package already defines -- or of raw bits, by defining r*.

Source code in src/zarr_metadata/v3/_registry.py
def extended_with(self, *definitions: Definition[Any]) -> Context:
    """This scope, plus definitions of your own.

    A name already filed under the same kind is taken over by what is
    passed here, which is how a reader substitutes its own reading of a
    codec the package already defines -- or of raw bits, by defining
    `r*`.
    """
    return Context.of(*self.definitions(), *definitions)

joined classmethod

joined(*contexts: Context) -> Context

The least scope that files everything each of contexts files: their join.

ScopeConflictError when two of them file different definitions under one name of one kind; extended_with is for taking a name over on purpose.

Source code in src/zarr_metadata/v3/_registry.py
@classmethod
def joined(cls, *contexts: Context) -> Context:
    """The least scope that files everything each of `contexts` files: their join.

    `ScopeConflictError` when two of them file different definitions
    under one name of one kind; `extended_with` is for taking a name
    over on purpose.
    """
    filed: dict[tuple[type[Definition[Any]], str], Definition[Any]] = {}
    conflicts: list[Conflict] = []
    for context in contexts:
        for kind, table in context.tables.items():
            for name, definition in table.items():
                held = filed.get((kind, name))
                if held is not None and held != definition:
                    conflicts.append(Conflict((kind, name), held, definition))
                    continue
                filed[kind, name] = definition
    if len(conflicts) != 0:
        raise ScopeConflictError(conflicts)
    return cls.of(*filed.values())

of classmethod

of(*definitions: Definition[Any]) -> Context

A scope of exactly these definitions; a later one takes a name over from an earlier.

TypeError for a definition of no kind, which no position in a document could hold.

Source code in src/zarr_metadata/v3/_registry.py
@classmethod
def of(cls, *definitions: Definition[Any]) -> Context:
    """A scope of exactly these definitions; a later one takes a name over from an earlier.

    `TypeError` for a definition of no kind, which no position in a
    document could hold.
    """
    tables: dict[type[Definition[Any]], dict[str, Definition[Any]]] = {}
    for definition in definitions:
        kind = kind_of(definition)
        if kind is None:
            msg = (
                f"{definition.name!r} is a definition of no kind; build it as a "
                "CodecDefinition, DataTypeDefinition, ChunkGridDefinition, "
                "ChunkKeyEncodingDefinition or StorageTransformerDefinition, or as a "
                "kind of your own"
            )
            raise TypeError(msg)
        tables.setdefault(kind, {})[definition.name] = definition
    return cls(
        MappingProxyType({kind: MappingProxyType(table) for kind, table in tables.items()})
    )

Disagreements dataclass

Where a scope reads a reading's claims otherwise: the names it would gain a meaning for, and those it conflicts with, a lost meaning among them.

Source code in src/zarr_metadata/v3/_scope.py
@dataclass(frozen=True, slots=True)
class Disagreements:
    """Where a scope reads a reading's claims otherwise: the names it would gain a meaning for, and those it conflicts with, a lost meaning among them."""

    gains: tuple[ClaimKey, ...]
    conflicts: tuple[Conflict, ...]

    @property
    def agrees(self) -> bool:
        """Whether the scope reads every claim identically."""
        return len(self.gains) == 0 and len(self.conflicts) == 0

agrees property

agrees: bool

Whether the scope reads every claim identically.

RefusedField dataclass

Bases: Generic[D]

A field that could not be read -- not a field at all, not JSON, or refused by the definition that claims its name -- as its problems say.

Source code in src/zarr_metadata/v3/_definition.py
@dataclass(frozen=True, slots=True, kw_only=True)
class RefusedField(Generic[D]):
    """A field that could not be read -- not a field at all, not JSON, or refused by the definition that claims its name -- as its problems say."""

    json: JSONValue | UNSET
    """The field as written, refined: arrays as tuples; `UNSET` when it is not JSON, which no document holds."""
    name: str | None
    """The name it is written with; None when it names none."""
    read_as: type[Definition[Any]]
    """The kind of metadata it was read as."""
    definition: D | None = None
    """The definition that claims its name and refused it; None when nothing in scope claims it, or it names none."""
    nested: Nested = dataclasses.field(default_factory=_nothing_nested)
    """The fields its configuration holds, each as the scope read it; empty when its configuration was not checked against its TypedDict."""

    def __eq__(self, other: object) -> bool:
        if not is_field(other):
            return NotImplemented
        return field_key(self) == field_key(other)

    def __hash__(self) -> int:
        return hash(field_key(self))

    def __post_init__(self) -> None:
        # The runtime half of the annotations; `read_as` with its type
        # arguments dropped, as `resolve` drops them.
        kind = as_kind(self.read_as)
        object.__setattr__(self, "read_as", kind)
        definition = cast("object", self.definition)
        refusal = None if definition is None else _misread(definition, kind, self.name)
        if refusal is not None:
            raise TypeError(refusal)

definition class-attribute instance-attribute

definition: D | None = None

The definition that claims its name and refused it; None when nothing in scope claims it, or it names none.

json instance-attribute

json: JSONValue | UNSET

The field as written, refined: arrays as tuples; UNSET when it is not JSON, which no document holds.

name instance-attribute

name: str | None

The name it is written with; None when it names none.

nested class-attribute instance-attribute

nested: Nested = dataclasses.field(
    default_factory=_nothing_nested
)

The fields its configuration holds, each as the scope read it; empty when its configuration was not checked against its TypedDict.

read_as instance-attribute

read_as: type[Definition[Any]]

The kind of metadata it was read as.

ScopeConflictError

Bases: ValueError

Raised where two scopes, or a scope and a reading, give one name two meanings, or one would lose a meaning the other has.

Carries every conflict in .conflicts, as MetadataValidationError carries every problem.

Source code in src/zarr_metadata/v3/_scope.py
class ScopeConflictError(ValueError):
    """Raised where two scopes, or a scope and a reading, give one name two meanings, or one would lose a meaning the other has.

    Carries every conflict in `.conflicts`, as `MetadataValidationError`
    carries every problem.
    """

    def __init__(self, conflicts: Sequence[Conflict]) -> None:
        self.conflicts: tuple[Conflict, ...] = tuple(conflicts)
        super().__init__("; ".join(str(conflict) for conflict in self.conflicts))

UnclaimedField dataclass

A field nothing in scope claims: an extension the scope leaves unjudged, which is what keeps the format open.

Equal to another when it is written with the same name and configuration, however each was spelled: nothing in scope interprets its configuration, so it compares as JSON text, as field_key says.

Source code in src/zarr_metadata/v3/_definition.py
@dataclass(frozen=True, slots=True, kw_only=True)
class UnclaimedField:
    """A field nothing in scope claims: an extension the scope leaves unjudged, which is what keeps the format open.

    Equal to another when it is written with the same name and
    configuration, however each was spelled: nothing in scope interprets
    its configuration, so it compares as JSON text, as `field_key` says.
    """

    json: JSONValue
    """The field as written, refined: arrays as tuples; it takes no part in equality."""
    name: str
    """The name nothing in scope claims."""
    read_as: type[Definition[Any]]
    """The kind of metadata it was read as: what a definition that claimed it would be."""
    configuration: Mapping[str, JSONValue] = dataclasses.field(init=False)
    """The configuration as written, which nothing judged; empty when none is written."""

    def __eq__(self, other: object) -> bool:
        if not is_field(other):
            return NotImplemented
        return field_key(self) == field_key(other)

    def __hash__(self) -> int:
        return hash(field_key(self))

    def __post_init__(self) -> None:
        # The runtime half of the annotations; `read_as` with its type
        # arguments dropped, as `resolve` drops them.
        object.__setattr__(self, "read_as", as_kind(self.read_as))
        name = cast("object", self.name)
        if not isinstance(name, str) or not self.read_as.well_named(name):
            msg = (
                "a field nothing in scope claims is named as a document names a "
                f"{self.read_as.label}, got {name!r}"
            )
            raise TypeError(msg)
        _, written, _ = self.read_as.named_configuration(self.json)
        configuration: Mapping[str, object] = {} if written is None else written
        object.__setattr__(self, "configuration", cast("Mapping[str, JSONValue]", configuration))

    @property
    def definition(self) -> None:
        """The definition that read it: none did."""
        return None

    @property
    def nested(self) -> Nested:
        """The fields its configuration holds as the scope read them: none, since nothing read its configuration."""
        return _nothing_nested()

    def to_json(self) -> JSONValue:
        """The field as a document writes it, sharing nothing with the field: its configuration as written, in the envelope every reader takes, as `AcceptedField.to_json` writes one."""
        return copied(written_json(self))

configuration class-attribute instance-attribute

configuration: Mapping[str, JSONValue] = dataclasses.field(
    init=False
)

The configuration as written, which nothing judged; empty when none is written.

definition property

definition: None

The definition that read it: none did.

json instance-attribute

json: JSONValue

The field as written, refined: arrays as tuples; it takes no part in equality.

name instance-attribute

name: str

The name nothing in scope claims.

nested property

nested: Nested

The fields its configuration holds as the scope read them: none, since nothing read its configuration.

read_as instance-attribute

read_as: type[Definition[Any]]

The kind of metadata it was read as: what a definition that claimed it would be.

to_json

to_json() -> JSONValue

The field as a document writes it, sharing nothing with the field: its configuration as written, in the envelope every reader takes, as AcceptedField.to_json writes one.

Source code in src/zarr_metadata/v3/_definition.py
def to_json(self) -> JSONValue:
    """The field as a document writes it, sharing nothing with the field: its configuration as written, in the envelope every reader takes, as `AcceptedField.to_json` writes one."""
    return copied(written_json(self))

ZarrV2CodecDefinition dataclass

Bases: Definition[C]

A v2 codec: a numcodecs id, and the TypedDict its parameters are.

A document writes {"id": name, **parameters}; the definition's configuration is the parameters, read at the field itself.

Source code in src/zarr_metadata/v2/_definition.py
@dataclass(frozen=True, kw_only=True, slots=True, repr=False)
class ZarrV2CodecDefinition(Definition[C], kind=True):
    """A v2 codec: a numcodecs id, and the TypedDict its parameters are.

    A document writes `{"id": name, **parameters}`; the definition's
    configuration is the parameters, read at the field itself.
    """

    label: ClassVar[str] = "v2 codec"

    @classmethod
    def name_problem(cls, name: str, at: Loc) -> ValidationProblem | None:
        if len(name) != 0:
            return None
        return ValidationProblem(at, "expected a codec id, got ''", "invalid_value")

    @classmethod
    def named_configuration(
        cls, value: object
    ) -> tuple[str | None, Mapping[str, object] | None, Problems]:
        if not is_object(value):
            return None, None, ()
        name = value.get("id")
        if not isinstance(name, str):
            return None, None, ()
        return (
            name,
            {key: item for key, item in value.items() if isinstance(key, str) and key != "id"},
            (),
        )

    @classmethod
    def envelope_problems(cls, value: object) -> Problems:
        if not is_object(value):
            return (
                ValidationProblem(
                    (), "expected a codec configuration with a string 'id'", "invalid_type"
                ),
            )
        entry = value
        if "id" not in entry:
            return (ValidationProblem(("id",), "missing required key", "missing_key"),)
        if not isinstance(entry["id"], str):
            return (
                ValidationProblem(
                    ("id",),
                    f"expected a string codec id, got {shown(entry['id'])}",
                    "invalid_type",
                ),
            )
        bad = cls.name_problem(entry["id"], ("id",))
        return () if bad is None else (bad,)

    @classmethod
    def envelope_json(cls, name: str, configuration: Mapping[str, JSONValue]) -> JSONValue:
        return {"id": name, **configuration}

    @classmethod
    def configuration_loc(cls, loc: Loc) -> Loc:
        return loc

    @classmethod
    def name_loc(cls, loc: Loc) -> Loc:
        return (*loc, "id")

label class-attribute

label: str = 'v2 codec'

The kind as a message names it: "codec".

configuration_loc classmethod

configuration_loc(loc: Loc) -> Loc

Where the configuration of a field at loc sits: under configuration for v3; at the field for a format that writes the parameters beside the name.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def configuration_loc(cls, loc: Loc) -> Loc:
    return loc

envelope_json classmethod

envelope_json(
    name: str, configuration: Mapping[str, JSONValue]
) -> JSONValue

A field of name and configuration as a document of the format writes it, in the fewest words every reader takes: for v3, an object.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def envelope_json(cls, name: str, configuration: Mapping[str, JSONValue]) -> JSONValue:
    return {"id": name, **configuration}

envelope_problems classmethod

envelope_problems(value: object) -> Problems

Every reason value is not a field's envelope as the format writes one for this kind, what the configuration holds left unjudged.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def envelope_problems(cls, value: object) -> Problems:
    if not is_object(value):
        return (
            ValidationProblem(
                (), "expected a codec configuration with a string 'id'", "invalid_type"
            ),
        )
    entry = value
    if "id" not in entry:
        return (ValidationProblem(("id",), "missing required key", "missing_key"),)
    if not isinstance(entry["id"], str):
        return (
            ValidationProblem(
                ("id",),
                f"expected a string codec id, got {shown(entry['id'])}",
                "invalid_type",
            ),
        )
    bad = cls.name_problem(entry["id"], ("id",))
    return () if bad is None else (bad,)

name_loc classmethod

name_loc(loc: Loc) -> Loc

Where the name of a field at loc, written as an object, sits: under name for v3.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def name_loc(cls, loc: Loc) -> Loc:
    return (*loc, "id")

name_problem classmethod

name_problem(
    name: str, at: Loc
) -> ValidationProblem | None

The problem name, at at, is when no document of the format writes it for a field of this kind; None when one may: for Zarr v3, when the spec gives an extension such a name.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def name_problem(cls, name: str, at: Loc) -> ValidationProblem | None:
    if len(name) != 0:
        return None
    return ValidationProblem(at, "expected a codec id, got ''", "invalid_value")

named_configuration classmethod

named_configuration(
    value: object,
) -> tuple[
    str | None, Mapping[str, object] | None, Problems
]

value, a field as a document of the format writes it, split into (name, configuration, problems), as the module's named_configuration splits a v3 field.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def named_configuration(
    cls, value: object
) -> tuple[str | None, Mapping[str, object] | None, Problems]:
    if not is_object(value):
        return None, None, ()
    name = value.get("id")
    if not isinstance(name, str):
        return None, None, ()
    return (
        name,
        {key: item for key, item in value.items() if isinstance(key, str) and key != "id"},
        (),
    )

ZarrV2DataTypeDefinition dataclass

Bases: WithFillValue[C]

A v2 data type: one family of NumPy types, and the fill value an array of it takes.

Filed under the family -- float -- and read for every typestr of the family, whose byte order, size and unit are its configuration; the rules say which of those the family takes. struct is read for an array of field records, its configuration {"fields": records}, so a problem in a record is located under fields: at ("dtype", "fields", 0, 1) for the type of the first record.

Source code in src/zarr_metadata/v2/_definition.py
@dataclass(frozen=True, kw_only=True, slots=True, repr=False)
class ZarrV2DataTypeDefinition(WithFillValue[C], kind=True):
    """A v2 data type: one family of NumPy types, and the fill value an array of it takes.

    Filed under the family -- `float` -- and read for every typestr of
    the family, whose byte order, size and unit are its configuration;
    the rules say which of those the family takes. `struct` is read for
    an array of field records, its configuration `{"fields": records}`,
    so a problem in a record is located under `fields`: at
    `("dtype", "fields", 0, 1)` for the type of the first record.
    """

    label: ClassVar[str] = "v2 data type"
    field_aliases: ClassVar[tuple[TypeAliasType, ...]] = (ZarrV2DataTypeField,)

    def _refusal(self) -> str | None:
        if parse_typestr(self.name) is not None:
            return (
                f"{self.name!r} is how a document writes one type of a family, which reads as "
                "the family; define the family"
            )
        # Named, not a bare `super()`: a dataclass with slots is rebuilt.
        return super(ZarrV2DataTypeDefinition, self)._refusal()

    @classmethod
    def name_problem(cls, name: str, at: Loc) -> ValidationProblem | None:
        return typestr_problem(name, at)

    @classmethod
    def spelled(cls, name: str) -> tuple[str | None, dict[str, JSONValue] | None]:
        if name == STRUCT_NAME:
            return name, None
        if name in FAMILIES.values():
            return None, None
        parsed = parse_typestr(name)
        if parsed is None:
            return name, None
        code, carried = parsed
        family = FAMILIES.get(code)
        if family is None:
            return name, None
        return family, carried

    def carrying_name(self, configuration: Mapping[str, JSONValue]) -> str | None:
        if self.name == STRUCT_NAME:
            return None
        code = next(code for code, family in FAMILIES.items() if family == self.name)
        name = f"{configuration['byteorder']}{code}{configuration.get('itemsize', '')}"
        if "unit" in configuration:
            factor = configuration.get("scale_factor", 1)
            name += f"[{'' if factor == 1 else factor}{configuration['unit']}]"
        return name

    @classmethod
    def named_configuration(
        cls, value: object
    ) -> tuple[str | None, Mapping[str, object] | None, Problems]:
        if isinstance(value, str):
            return value, None, ()
        if isinstance(value, (list, tuple)):
            return STRUCT_NAME, {"fields": cast("JSONValue", value)}, ()
        return None, None, ()

    @classmethod
    def envelope_problems(cls, value: object) -> Problems:
        if isinstance(value, str):
            bad = typestr_problem(value, ())
            return () if bad is None else (bad,)
        if isinstance(value, (list, tuple)):
            return ()
        return (
            ValidationProblem(
                (),
                "expected a v2 dtype -- a NumPy typestr, or an array of field records -- got "
                f"{shown(value)}",
                "invalid_type",
            ),
        )

    @classmethod
    def envelope_json(cls, name: str, configuration: Mapping[str, JSONValue]) -> JSONValue:
        if name == STRUCT_NAME and "fields" in configuration:
            return configuration["fields"]
        return name

    @classmethod
    def configuration_loc(cls, loc: Loc) -> Loc:
        return loc

    @classmethod
    def name_loc(cls, loc: Loc) -> Loc:
        return loc

field_aliases class-attribute

field_aliases: tuple[TypeAliasType, ...] = (
    ZarrV2DataTypeField,
)

The field aliases a configuration member holding a field of this kind is annotated with: CodecField and StaticCodecField for a codec.

label class-attribute

label: str = 'v2 data type'

The kind as a message names it: "codec".

carrying_name

carrying_name(
    configuration: Mapping[str, JSONValue],
) -> str | None

The name that carries configuration for this definition, the inverse of spelled: r16 for r* with {"bits": 16}; None when its names carry nothing.

Source code in src/zarr_metadata/v2/_definition.py
def carrying_name(self, configuration: Mapping[str, JSONValue]) -> str | None:
    if self.name == STRUCT_NAME:
        return None
    code = next(code for code, family in FAMILIES.items() if family == self.name)
    name = f"{configuration['byteorder']}{code}{configuration.get('itemsize', '')}"
    if "unit" in configuration:
        factor = configuration.get("scale_factor", 1)
        name += f"[{'' if factor == 1 else factor}{configuration['unit']}]"
    return name

configuration_loc classmethod

configuration_loc(loc: Loc) -> Loc

Where the configuration of a field at loc sits: under configuration for v3; at the field for a format that writes the parameters beside the name.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def configuration_loc(cls, loc: Loc) -> Loc:
    return loc

envelope_json classmethod

envelope_json(
    name: str, configuration: Mapping[str, JSONValue]
) -> JSONValue

A field of name and configuration as a document of the format writes it, in the fewest words every reader takes: for v3, an object.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def envelope_json(cls, name: str, configuration: Mapping[str, JSONValue]) -> JSONValue:
    if name == STRUCT_NAME and "fields" in configuration:
        return configuration["fields"]
    return name

envelope_problems classmethod

envelope_problems(value: object) -> Problems

Every reason value is not a field's envelope as the format writes one for this kind, what the configuration holds left unjudged.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def envelope_problems(cls, value: object) -> Problems:
    if isinstance(value, str):
        bad = typestr_problem(value, ())
        return () if bad is None else (bad,)
    if isinstance(value, (list, tuple)):
        return ()
    return (
        ValidationProblem(
            (),
            "expected a v2 dtype -- a NumPy typestr, or an array of field records -- got "
            f"{shown(value)}",
            "invalid_type",
        ),
    )

name_loc classmethod

name_loc(loc: Loc) -> Loc

Where the name of a field at loc, written as an object, sits: under name for v3.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def name_loc(cls, loc: Loc) -> Loc:
    return loc

name_problem classmethod

name_problem(
    name: str, at: Loc
) -> ValidationProblem | None

The problem name, at at, is when no document of the format writes it for a field of this kind; None when one may: for Zarr v3, when the spec gives an extension such a name.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def name_problem(cls, name: str, at: Loc) -> ValidationProblem | None:
    return typestr_problem(name, at)

named_configuration classmethod

named_configuration(
    value: object,
) -> tuple[
    str | None, Mapping[str, object] | None, Problems
]

value, a field as a document of the format writes it, split into (name, configuration, problems), as the module's named_configuration splits a v3 field.

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def named_configuration(
    cls, value: object
) -> tuple[str | None, Mapping[str, object] | None, Problems]:
    if isinstance(value, str):
        return value, None, ()
    if isinstance(value, (list, tuple)):
        return STRUCT_NAME, {"fields": cast("JSONValue", value)}, ()
    return None, None, ()

spelled classmethod

spelled(
    name: str,
) -> tuple[str | None, dict[str, JSONValue] | None]

How a name a document writes reads: the name its definition is filed under, and the configuration the name carries.

A name is filed as itself and carries nothing, (name, None). A kind whose names carry configuration says otherwise: a v3 data type r16 is filed under r* with {"bits": 16}. A name no document writes, which only files a definition, is (None, None).

Source code in src/zarr_metadata/v2/_definition.py
@classmethod
def spelled(cls, name: str) -> tuple[str | None, dict[str, JSONValue] | None]:
    if name == STRUCT_NAME:
        return name, None
    if name in FAMILIES.values():
        return None, None
    parsed = parse_typestr(name)
    if parsed is None:
        return name, None
    code, carried = parsed
    family = FAMILIES.get(code)
    if family is None:
        return name, None
    return family, carried

canonical_fill_value

canonical_fill_value(
    data_type: ResolvedField[F], value: object
) -> JSONValue | UNSET

value, a fill value of data_type, a data type field a scope read, in the one spelling its value has; UNSET when it has a problem.

As the data type's fill_value_canonical spells it, so two fill values of a data type are one value exactly when their canonical spellings are written alike -- the same JSON, as json.dumps writes it, which == is not: it takes -0.0 for 0.0. A fill value fill_value_problems finds a problem with has no canonical spelling, as canonical_of gives a field with a problem none: UNSET, since None is the JSON null, a fill value of a data type the scope did not read, which spells a fill value as written.

Source code in src/zarr_metadata/v3/_definition.py
def canonical_fill_value(data_type: ResolvedField[F], value: object) -> JSONValue | UNSET:
    """`value`, a fill value of `data_type`, a data type field a scope read, in the one spelling its value has; `UNSET` when it has a problem.

    As the data type's `fill_value_canonical` spells it, so two fill
    values of a data type are one value exactly when their canonical
    spellings are written alike -- the same JSON, as `json.dumps` writes
    it, which `==` is not: it takes `-0.0` for `0.0`. A fill value
    `fill_value_problems` finds a problem with has no canonical spelling,
    as `canonical_of` gives a field with a problem none: `UNSET`, since
    `None` is the JSON `null`, a fill value of a data type the scope did
    not read, which spells a fill value as written.
    """
    if len(fill_value_problems(data_type, value)) != 0:
        return UNSET
    refined, _ = refine_json(value, ())
    return spelled_canonically(data_type, refined)

fill_value_problems

fill_value_problems(
    data_type: ResolvedField[F],
    value: object,
    loc: Loc = (),
) -> Problems

What is wrong with value as a fill value of data_type, a data type field a scope read.

value is refined to JSON first: not JSON is the first verdict, whatever the data type. It is then checked against the JSON shape the data type's definition declares, and judged by its fill value rules, as read_configuration reads a configuration: a key the shape does not declare is reported and left out, and the rules still judge the rest. The rules see the fields the configuration holds as the scope read them: a struct judges each field's fill value by that field's own type. A data type the scope did not read, out of scope or invalid, leaves a JSON fill value unjudged. loc prefixes every problem.

Source code in src/zarr_metadata/v3/_definition.py
def fill_value_problems(data_type: ResolvedField[F], value: object, loc: Loc = ()) -> Problems:
    """What is wrong with `value` as a fill value of `data_type`, a data type field a scope read.

    `value` is refined to JSON first: not JSON is the first verdict,
    whatever the data type. It is then checked against the JSON shape the
    data type's definition declares, and judged by its fill value rules, as
    `read_configuration` reads a configuration: a key the shape does not declare is
    reported and left out, and the rules still judge the rest. The rules
    see the fields the configuration holds as the scope read them: a
    struct judges each field's fill value by that field's own type. A data
    type the scope did not read, out of scope or invalid, leaves a JSON fill
    value unjudged. `loc` prefixes every problem.
    """
    refined, problems = refine_json(value, loc)
    if len(problems) != 0 or not isinstance(data_type, AcceptedField):
        return with_input(problems, value, loc)
    definition, configuration = data_type.definition, data_type.configuration
    typed, problems = _fill_value_parser(definition.fill_value)(refined, loc)
    if not _usable(problems):
        return with_input(problems, value, loc)
    refused = ruled(
        definition,
        lambda: definition.fill_value_rules(read_only(configuration), data_type.nested, typed),
        loc,
    )
    return with_input((*problems, *refused), value, loc)

resolve_codec_v2

resolve_codec_v2(
    value: object,
    context: Context | None = None,
    loc: Loc = (),
) -> tuple[
    ResolvedField[ZarrV2CodecDefinition[Any]], Problems
]

value, a v2 compressor or one of its filters, read in context, CORE_V2 when none is given: what the scope made of it, and every problem, each prefixed with loc.

Source code in src/zarr_metadata/v2/definition.py
def resolve_codec_v2(
    value: object, context: Context | None = None, loc: Loc = ()
) -> tuple[ResolvedField[ZarrV2CodecDefinition[Any]], Problems]:
    """`value`, a v2 `compressor` or one of its `filters`, read in `context`, `CORE_V2` when none is given: what the scope made of it, and every problem, each prefixed with `loc`."""
    return resolve(value, ZarrV2CodecDefinition, CORE_V2 if context is None else context, loc)

resolve_dtype_v2

resolve_dtype_v2(
    value: object,
    context: Context | None = None,
    loc: Loc = (),
) -> tuple[
    ResolvedField[ZarrV2DataTypeDefinition[Any]], Problems
]

value, a v2 dtype, read in context, CORE_V2 when none is given: what the scope made of it, and every problem, each prefixed with loc.

Source code in src/zarr_metadata/v2/definition.py
def resolve_dtype_v2(
    value: object, context: Context | None = None, loc: Loc = ()
) -> tuple[ResolvedField[ZarrV2DataTypeDefinition[Any]], Problems]:
    """`value`, a v2 `dtype`, read in `context`, `CORE_V2` when none is given: what the scope made of it, and every problem, each prefixed with `loc`."""
    return resolve(value, ZarrV2DataTypeDefinition, CORE_V2 if context is None else context, loc)

zarr_metadata.v2.data_type

The data types zarr-python 2.x writes, one definition per NumPy family.

BOOL_V2 module-attribute

BOOL_V2: Final = ZarrV2DataTypeDefinition(
    name="bool",
    configuration=ZarrV2ScalarConfiguration,
    rules=sized((1,), None),
    canonical=orderless_at(None),
    fill_value=bool | None,
)

|b1: one byte, true or false.

BYTES_V2 module-attribute

BYTES_V2: Final = ZarrV2DataTypeDefinition(
    name="bytes",
    configuration=ZarrV2ScalarConfiguration,
    rules=sized(None, None),
    canonical=orderless_at(None),
    fill_value=ZarrV2Base64FillValue,
    fill_value_rules=base64_fill_value_rules,
)

|S<n>: byte strings of n bytes; the fill value base64 of one.

COMPLEX_V2 module-attribute

COMPLEX_V2: Final = ZarrV2DataTypeDefinition(
    name="complex",
    configuration=ZarrV2ScalarConfiguration,
    rules=sized((8, 16), frozenset()),
    fill_value=ZarrV2ComplexFillValue,
    fill_value_canonical=_complex_canonical,
)

c8, c16: complex floats; the fill value [real, imag].

DATETIME64_V2 module-attribute

DATETIME64_V2: Final = ZarrV2DataTypeDefinition(
    name="datetime64",
    configuration=ZarrV2TimeConfiguration,
    rules=_rules,
    canonical=_canonical,
    fill_value=ZarrV2TimeFillValue,
    fill_value_canonical=_fill_value_canonical,
)

<M8[unit]: a moment, as ticks of the unit since the epoch.

FLOAT_V2 module-attribute

FLOAT_V2: Final = ZarrV2DataTypeDefinition(
    name="float",
    configuration=ZarrV2ScalarConfiguration,
    rules=sized((2, 4, 8), frozenset()),
    fill_value=ZarrV2FloatFillValue,
    fill_value_canonical=_float_canonical,
)

f2, f4, f8: IEEE 754 floats; the fill value a number or a named non-finite value.

INT_V2 module-attribute

INT_V2: Final = ZarrV2DataTypeDefinition(
    name="int",
    configuration=ZarrV2ScalarConfiguration,
    rules=sized((1, 2, 4, 8), _ONE_BYTE),
    canonical=orderless_at(_ONE_BYTE),
    fill_value=int | None,
    fill_value_rules=_InRange(True),
)

i1 to i8: signed integers, the fill value in the type's range.

OBJECT_V2 module-attribute

OBJECT_V2: Final = ZarrV2DataTypeDefinition(
    name="object",
    configuration=ZarrV2ObjectConfiguration,
    canonical=_canonical,
)

|O: Python objects, each encoded by a filter; the fill value any JSON.

STRUCT_V2 module-attribute

STRUCT_V2: Final = ZarrV2DataTypeDefinition(
    name=STRUCT_NAME,
    configuration=ZarrV2StructConfiguration,
    rules=_rules,
    fill_value=ZarrV2Base64FillValue,
    fill_value_rules=base64_fill_value_rules,
)

A structured type: an array of field records; the fill value base64 of one record (https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v2/v2.0.rst#L191-L193).

STR_V2 module-attribute

STR_V2: Final = ZarrV2DataTypeDefinition(
    name="str",
    configuration=ZarrV2ScalarConfiguration,
    rules=sized(None, frozenset()),
    fill_value=str | None,
)

<U<n>: strings of n code points, each four bytes in the byte order written; the fill value a string.

TIMEDELTA64_V2 module-attribute

TIMEDELTA64_V2: Final = ZarrV2DataTypeDefinition(
    name="timedelta64",
    configuration=ZarrV2TimeConfiguration,
    rules=_rules,
    canonical=_canonical,
    fill_value=ZarrV2TimeFillValue,
    fill_value_canonical=_fill_value_canonical,
)

<m8[unit]: a duration, as ticks of the unit.

UINT_V2 module-attribute

UINT_V2: Final = ZarrV2DataTypeDefinition(
    name="uint",
    configuration=ZarrV2ScalarConfiguration,
    rules=sized((1, 2, 4, 8), _ONE_BYTE),
    canonical=orderless_at(_ONE_BYTE),
    fill_value=int | None,
    fill_value_rules=_InRange(False),
)

u1 to u8: unsigned integers, the fill value in the type's range.

V2_DATA_TYPES module-attribute

Every v2 data type, by family.

VOID_V2 module-attribute

VOID_V2: Final = ZarrV2DataTypeDefinition(
    name="void",
    configuration=ZarrV2ScalarConfiguration,
    rules=sized(None, None),
    canonical=orderless_at(None),
    fill_value=ZarrV2Base64FillValue,
    fill_value_rules=base64_fill_value_rules,
)

|V<n>: n bytes of no type; the fill value base64 of them.

__all__ module-attribute

__all__ = [
    "BOOL_V2",
    "BYTES_V2",
    "COMPLEX_V2",
    "DATETIME64_V2",
    "FLOAT_V2",
    "INT_V2",
    "OBJECT_V2",
    "STRUCT_V2",
    "STR_V2",
    "TIMEDELTA64_V2",
    "UINT_V2",
    "V2_DATA_TYPES",
    "VOID_V2",
]