Skip to content

zarr_metadata.v3.chunk_key_encoding

zarr_metadata.v3.chunk_key_encoding

Zarr v3 chunk key encoding metadata types.

Each chunk key encoding lives in its own submodule:

  • default -- v3 default encoding (/-separated)
  • v2 -- v2-compatibility encoding (.-separated by default)

Both are defined by the v3 core spec: https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/chunk-key-encodings/default/index.rst https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/chunk-key-encodings/v2/index.rst

The <X>ChunkKeyEncodingMetadata aliases re-exported here are the canonical type for each encoding's permitted JSON shapes. For the underlying <X>ChunkKeyEncodingObject, <X>ChunkKeyEncodingConfiguration, etc., import directly from the leaf submodule.

See https://zarr-specs.readthedocs.io/en/latest/v3/core/index.html#chunk-key-encoding

zarr_metadata.v3.chunk_key_encoding.default

Default chunk key encoding (Zarr v3 core spec).

The chunk key for a chunk with grid index (k, j, i, ...) is formed by appending c<sep>k<sep>j<sep>i... (where <sep> is separator).

See https://zarr-specs.readthedocs.io/en/latest/v3/core/index.html#chunk-key-encoding

DEFAULT_CHUNK_KEY_ENCODING_NAME module-attribute

DEFAULT_CHUNK_KEY_ENCODING_NAME: Final = 'default'

The name field value of the default chunk key encoding.

DEFAULT_CHUNK_KEY_ENCODING_SEPARATOR module-attribute

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

Tuple of permitted values for the separator field of the default chunk key encoding.

DefaultChunkKeyEncodingMetadata module-attribute

DefaultChunkKeyEncodingMetadata = (
    DefaultChunkKeyEncodingObject
    | DefaultChunkKeyEncodingName
)

Permitted JSON shapes for the default chunk-key encoding metadata.

The configuration has no required keys (separator defaults to "/"), so the short-hand-name form is permitted in addition to the object form.

DefaultChunkKeyEncodingName module-attribute

DefaultChunkKeyEncodingName = Literal['default']

Literal type of the name field of the default chunk key encoding.

DefaultChunkKeyEncodingSeparator module-attribute

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

Literal type of permitted separator values for the default chunk key encoding.

Defaults to "/" if absent.

__all__ module-attribute

__all__ = [
    "DEFAULT_CHUNK_KEY_ENCODING_NAME",
    "DEFAULT_CHUNK_KEY_ENCODING_SEPARATOR",
    "DefaultChunkKeyEncoding",
    "DefaultChunkKeyEncodingConfiguration",
    "DefaultChunkKeyEncodingMetadata",
    "DefaultChunkKeyEncodingName",
    "DefaultChunkKeyEncodingObject",
    "DefaultChunkKeyEncodingSeparator",
]

DefaultChunkKeyEncoding dataclass

Bases: MetadataEntity

The default chunk key encoding, coerced from its metadata.

Source code in src/zarr_metadata/v3/chunk_key_encoding/default.py
@dataclass(frozen=True)
class DefaultChunkKeyEncoding(MetadataEntity):
    """The `default` chunk key encoding, coerced from its metadata."""

    separator: DefaultChunkKeyEncodingSeparator | UNSET = UNSET

    identifier: ClassVar[str] = DEFAULT_CHUNK_KEY_ENCODING_NAME

    member_types: ClassVar[MemberTypes] = {
        "separator": (False, one_of(DEFAULT_CHUNK_KEY_ENCODING_SEPARATOR))
    }

    def to_json(self) -> DefaultChunkKeyEncodingObject | DefaultChunkKeyEncodingName:
        return cast(
            "DefaultChunkKeyEncodingObject | DefaultChunkKeyEncodingName", super().to_json()
        )

configuration_required class-attribute

configuration_required: bool = False

Whether the bare-name spelling says too little for this entity.

The spec permits a bare name "if no configuration metadata is required", so this is true exactly when some member is required.

identifier class-attribute

The name this entity is registered under.

Usually the name the metadata carries. The raw-bytes data types are the exception: every r<N> spelling is one family, so the family gets an invented identifier that no real name can collide with.

member_types class-attribute

member_types: MemberTypes = {
    "separator": (
        False,
        one_of(DEFAULT_CHUNK_KEY_ENCODING_SEPARATOR),
    )
}

The configuration members, and the type each one takes.

The same keys as the configuration TypedDict, which is the same as the constructor signature; tests/v3/test_entities.py holds the three together.

must_understand class-attribute instance-attribute

must_understand: bool = field(default=True, kw_only=True)

name property

name: str

The name this entity carries, as a document would write it.

Usually the identifier. They differ for the raw-bytes family, whose identifier is invented and belongs in no message a reader sees -- so anything user-facing wants this, and anything looking something up wants identifier.

required_class_vars class-attribute

required_class_vars: tuple[str, ...] = ('identifier',)

Every class variable a concrete entity of this kind must declare.

separator class-attribute instance-attribute

__init__

__init__(
    separator: DefaultChunkKeyEncodingSeparator
    | UNSET = UNSET,
    *,
    must_understand: bool = True,
) -> None

__init_subclass__

__init_subclass__(
    *, base: bool = False, **kwargs: object
) -> None

Refuse a subclass that forgot to say what it is.

identifier and the per-kind class variables carry no default, so a subclass omitting one type-checks cleanly and then raises AttributeError from whichever method is reached first. Saying so here makes it an import-time error in the extension's own module.

base=True for a class that exists to add a class variable rather than to be an entity -- CodecEntity, IntegerDataType.

Source code in src/zarr_metadata/v3/_entity.py
def __init_subclass__(cls, *, base: bool = False, **kwargs: object) -> None:
    """Refuse a subclass that forgot to say what it is.

    `identifier` and the per-kind class variables carry no default,
    so a subclass omitting one type-checks cleanly and then raises
    `AttributeError` from whichever method is reached first. Saying so
    here makes it an import-time error in the extension's own module.

    `base=True` for a class that exists to add a class variable
    rather than to be an entity -- `CodecEntity`, `IntegerDataType`.
    """
    super().__init_subclass__(**kwargs)
    if base:
        return
    missing = [name for name in cls.required_class_vars if not hasattr(cls, name)]
    if len(missing) != 0:
        msg = f"{cls.__name__} does not declare {', '.join(missing)}"
        raise TypeError(msg)
    # An optional member defaults to UNSET or `configuration` emits it
    # for every instance, so the bare-name spelling becomes
    # unreachable and a document gains a member it never wrote.
    invented = [
        key
        for key, (required, _) in cls.member_types.items()
        if not required and getattr(cls, key, UNSET) is not UNSET
    ]
    if len(invented) != 0:
        msg = (
            f"{cls.__name__} gives the optional member(s) "
            f"{', '.join(invented)} a default other than UNSET"
        )
        raise TypeError(msg)

accepts classmethod

accepts(name: str) -> bool

Whether name denotes this entity.

Constant for all but the raw-bytes family, where one class covers every r<N>.

Source code in src/zarr_metadata/v3/_entity.py
@classmethod
def accepts(cls, name: str) -> bool:
    """Whether `name` denotes this entity.

    Constant for all but the raw-bytes family, where one class covers
    every `r<N>`.
    """
    return name == cls.identifier

canonical

canonical() -> Self

This entity in the simplest form that means the same thing.

A transformation, asked for by canonicalize_array_metadata_v3 and by nothing else. to_json does not apply it, because writing a document back is not the same as asking for it to be rewritten: a reader that reads and writes should not change bytes it was not asked to change.

Default: entities are already canonical. Override where two spellings of a member mean the same -- a rectilinear dimension's run-length encoding, a typesize that noshuffle ignores -- and where a contained entity has its own canonical form.

Source code in src/zarr_metadata/v3/_entity.py
def canonical(self) -> Self:
    """This entity in the simplest form that means the same thing.

    A *transformation*, asked for by `canonicalize_array_metadata_v3`
    and by nothing else. `to_json` does not apply it, because writing
    a document back is not the same as asking for it to be rewritten:
    a reader that reads and writes should not change bytes it was not
    asked to change.

    Default: entities are already canonical. Override where two
    spellings of a member mean the same -- a rectilinear dimension's
    run-length encoding, a `typesize` that `noshuffle` ignores -- and
    where a contained entity has its own canonical form.
    """
    return self

coerce classmethod

coerce(value: object, context: Context) -> Coerced[Self]

value as this entity, or the reasons it is not one.

context is the scope this reading is happening in; most entities have no use for it and ignore it.

Source code in src/zarr_metadata/v3/_entity.py
@classmethod
def coerce(cls, value: object, context: Context) -> Coerced[Self]:
    """`value` as this entity, or the reasons it is not one.

    `context` is the scope this reading is happening in; most entities
    have no use for it and ignore it.
    """
    name, configuration, must_understand = named_configuration(value)
    if name is None or not cls.accepts(name):
        return None, problem((), f"expected the {cls.identifier!r} entity")
    if configuration is None:
        if cls.configuration_required:
            return None, problem(
                ("configuration",),
                f"{cls.identifier!r} requires a configuration",
                "missing_key",
            )
        configuration = cast("Mapping[str, object]", {})
    members, found, unreadable = coerce_members(configuration, cls.member_types)
    if len(unreadable) != 0:
        # The entity cannot be built, but the members that *did* read
        # can still be judged -- one bad member should not hide the
        # value problems of the ones beside it. Anything the partial
        # reading says about an unreadable member is its default
        # talking, so those are dropped.
        partial = cls(must_understand=must_understand, **members)  # type: ignore[arg-type]
        found = (
            *found,
            # `within`, because a partial reading reports relative to
            # the configuration and `coerce`'s caller does not insert
            # that segment -- `coerce_members` problems already carry it.
            *within(
                (),
                [
                    entry
                    for entry in partial.problems()
                    if entry.loc[:1] not in {(key,) for key in unreadable}
                ],
            ),
        )
        return None, found
    return cls(must_understand=must_understand, **members), found  # type: ignore[arg-type]

configuration

configuration() -> dict[str, object]

This entity's configuration, as the document would write it.

Faithful to every member the entity holds: to_json is serialization, not canonicalization, so nothing is simplified here. Override only to render a member that is not already JSON, such as a contained entity.

Absent optional members are left out, which is what makes the bare-name spelling reachable. Absence is UNSET, never None: this package holds None to mean a JSON null the document actually wrote, and scale_offset is a real case where null and absent are different documents.

Source code in src/zarr_metadata/v3/_entity.py
def configuration(self) -> dict[str, object]:
    """This entity's configuration, as the document would write it.

    Faithful to every member the entity holds: `to_json` is
    serialization, not canonicalization, so nothing is simplified
    here. Override only to render a member that is not already JSON,
    such as a contained entity.

    Absent optional members are left out, which is what makes the
    bare-name spelling reachable. Absence is `UNSET`, never `None`:
    this package holds `None` to mean a JSON `null` the document
    actually wrote, and `scale_offset` is a real case where `null`
    and absent are different documents.
    """
    return {
        key: value
        for key in type(self).member_types
        if (value := getattr(self, key)) is not UNSET
    }

problems

problems() -> tuple[ValidationProblem, ...]

Every value of this entity the spec disallows.

Locations are relative to the entity's configuration. Default: an entity whose type admits only valid values has nothing to add.

Source code in src/zarr_metadata/v3/_entity.py
def problems(self) -> tuple[ValidationProblem, ...]:
    """Every value of this entity the spec disallows.

    Locations are relative to the entity's `configuration`. Default:
    an entity whose type admits only valid values has nothing to add.
    """
    return ()

to_json

This entity as a document would write it.

Faithful to every member: read a document, write it back, and the members come out as they went in. Ask canonical first if you want the simplest equivalent spelling.

What is not preserved is the envelope's spelling, because the entity does not model it: a bare name, {"name": x}, and {"name": x, "configuration": {}} all mean the same and all read to the same entity, so all three write back as the bare name. must_understand is omitted when true, which is its default; an explicit false is kept, because that one says something.

Subclasses narrow the return type to their own object TypedDict, which is the JSON form this dataclass models.

Source code in src/zarr_metadata/v3/chunk_key_encoding/default.py
def to_json(self) -> DefaultChunkKeyEncodingObject | DefaultChunkKeyEncodingName:
    return cast(
        "DefaultChunkKeyEncodingObject | DefaultChunkKeyEncodingName", super().to_json()
    )

DefaultChunkKeyEncodingConfiguration

Bases: TypedDict

Configuration for the default chunk key encoding.

separator is optional and defaults to "/" per spec. https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/chunk-key-encodings/default/index.rst#L27-L29

Source code in src/zarr_metadata/v3/chunk_key_encoding/default.py
class DefaultChunkKeyEncodingConfiguration(TypedDict, closed=True):
    """Configuration for the default chunk key encoding.

    `separator` is optional and defaults to `"/"` per spec.
      https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/chunk-key-encodings/default/index.rst#L27-L29
    """

    separator: NotRequired[DefaultChunkKeyEncodingSeparator]

separator instance-attribute

DefaultChunkKeyEncodingObject

Bases: TypedDict

Default chunk key encoding metadata in object form.

Source code in src/zarr_metadata/v3/chunk_key_encoding/default.py
class DefaultChunkKeyEncodingObject(TypedDict, closed=True):
    """Default chunk key encoding metadata in object form."""

    name: DefaultChunkKeyEncodingName
    configuration: NotRequired[DefaultChunkKeyEncodingConfiguration]
    must_understand: NotRequired[bool]

configuration instance-attribute

must_understand instance-attribute

must_understand: NotRequired[bool]

name instance-attribute

zarr_metadata.v3.chunk_key_encoding.v2

v2-compatibility chunk key encoding (Zarr v3 core spec).

Intended only to allow existing v2 arrays to be converted to v3 without having to rename chunks. Not recommended for new arrays.

Naming note: these are Zarr v3 types. The leading V2 in V2ChunkKeyEncodingMetadata (and friends) is the encoding's registered entity name ("v2"), not the format-version marker that ZarrV2... names carry — this package's version-prefixed names always spell it ZarrV2 / ZarrV3.

See https://zarr-specs.readthedocs.io/en/latest/v3/core/index.html#chunk-key-encoding

V2ChunkKeyEncodingMetadata module-attribute

V2ChunkKeyEncodingMetadata = (
    V2ChunkKeyEncodingObject | V2ChunkKeyEncodingName
)

Permitted JSON shapes for the v2-compatibility chunk-key encoding metadata.

The configuration has no required keys (separator defaults to "."), so the short-hand-name form is permitted in addition to the object form.

V2ChunkKeyEncodingName module-attribute

V2ChunkKeyEncodingName = Literal['v2']

Literal type of the name field of the v2 chunk key encoding.

V2ChunkKeyEncodingSeparator module-attribute

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

Literal type of permitted separator values for the v2 chunk key encoding.

Defaults to "." if absent.

V2_CHUNK_KEY_ENCODING_NAME module-attribute

V2_CHUNK_KEY_ENCODING_NAME: Final = 'v2'

The name field value of the v2 chunk key encoding.

V2_CHUNK_KEY_ENCODING_SEPARATOR module-attribute

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

Tuple of permitted values for the separator field of the v2 chunk key encoding.

__all__ module-attribute

__all__ = [
    "V2_CHUNK_KEY_ENCODING_NAME",
    "V2_CHUNK_KEY_ENCODING_SEPARATOR",
    "V2ChunkKeyEncoding",
    "V2ChunkKeyEncodingConfiguration",
    "V2ChunkKeyEncodingMetadata",
    "V2ChunkKeyEncodingName",
    "V2ChunkKeyEncodingObject",
    "V2ChunkKeyEncodingSeparator",
]

V2ChunkKeyEncoding dataclass

Bases: MetadataEntity

The v2 chunk key encoding, coerced from its metadata.

Source code in src/zarr_metadata/v3/chunk_key_encoding/v2.py
@dataclass(frozen=True)
class V2ChunkKeyEncoding(MetadataEntity):
    """The `v2` chunk key encoding, coerced from its metadata."""

    separator: V2ChunkKeyEncodingSeparator | UNSET = UNSET

    identifier: ClassVar[str] = V2_CHUNK_KEY_ENCODING_NAME

    member_types: ClassVar[MemberTypes] = {
        "separator": (False, one_of(V2_CHUNK_KEY_ENCODING_SEPARATOR))
    }

    def to_json(self) -> V2ChunkKeyEncodingObject | V2ChunkKeyEncodingName:
        return cast("V2ChunkKeyEncodingObject | V2ChunkKeyEncodingName", super().to_json())

configuration_required class-attribute

configuration_required: bool = False

Whether the bare-name spelling says too little for this entity.

The spec permits a bare name "if no configuration metadata is required", so this is true exactly when some member is required.

identifier class-attribute

The name this entity is registered under.

Usually the name the metadata carries. The raw-bytes data types are the exception: every r<N> spelling is one family, so the family gets an invented identifier that no real name can collide with.

member_types class-attribute

member_types: MemberTypes = {
    "separator": (
        False,
        one_of(V2_CHUNK_KEY_ENCODING_SEPARATOR),
    )
}

The configuration members, and the type each one takes.

The same keys as the configuration TypedDict, which is the same as the constructor signature; tests/v3/test_entities.py holds the three together.

must_understand class-attribute instance-attribute

must_understand: bool = field(default=True, kw_only=True)

name property

name: str

The name this entity carries, as a document would write it.

Usually the identifier. They differ for the raw-bytes family, whose identifier is invented and belongs in no message a reader sees -- so anything user-facing wants this, and anything looking something up wants identifier.

required_class_vars class-attribute

required_class_vars: tuple[str, ...] = ('identifier',)

Every class variable a concrete entity of this kind must declare.

separator class-attribute instance-attribute

__init__

__init__(
    separator: V2ChunkKeyEncodingSeparator | UNSET = UNSET,
    *,
    must_understand: bool = True,
) -> None

__init_subclass__

__init_subclass__(
    *, base: bool = False, **kwargs: object
) -> None

Refuse a subclass that forgot to say what it is.

identifier and the per-kind class variables carry no default, so a subclass omitting one type-checks cleanly and then raises AttributeError from whichever method is reached first. Saying so here makes it an import-time error in the extension's own module.

base=True for a class that exists to add a class variable rather than to be an entity -- CodecEntity, IntegerDataType.

Source code in src/zarr_metadata/v3/_entity.py
def __init_subclass__(cls, *, base: bool = False, **kwargs: object) -> None:
    """Refuse a subclass that forgot to say what it is.

    `identifier` and the per-kind class variables carry no default,
    so a subclass omitting one type-checks cleanly and then raises
    `AttributeError` from whichever method is reached first. Saying so
    here makes it an import-time error in the extension's own module.

    `base=True` for a class that exists to add a class variable
    rather than to be an entity -- `CodecEntity`, `IntegerDataType`.
    """
    super().__init_subclass__(**kwargs)
    if base:
        return
    missing = [name for name in cls.required_class_vars if not hasattr(cls, name)]
    if len(missing) != 0:
        msg = f"{cls.__name__} does not declare {', '.join(missing)}"
        raise TypeError(msg)
    # An optional member defaults to UNSET or `configuration` emits it
    # for every instance, so the bare-name spelling becomes
    # unreachable and a document gains a member it never wrote.
    invented = [
        key
        for key, (required, _) in cls.member_types.items()
        if not required and getattr(cls, key, UNSET) is not UNSET
    ]
    if len(invented) != 0:
        msg = (
            f"{cls.__name__} gives the optional member(s) "
            f"{', '.join(invented)} a default other than UNSET"
        )
        raise TypeError(msg)

accepts classmethod

accepts(name: str) -> bool

Whether name denotes this entity.

Constant for all but the raw-bytes family, where one class covers every r<N>.

Source code in src/zarr_metadata/v3/_entity.py
@classmethod
def accepts(cls, name: str) -> bool:
    """Whether `name` denotes this entity.

    Constant for all but the raw-bytes family, where one class covers
    every `r<N>`.
    """
    return name == cls.identifier

canonical

canonical() -> Self

This entity in the simplest form that means the same thing.

A transformation, asked for by canonicalize_array_metadata_v3 and by nothing else. to_json does not apply it, because writing a document back is not the same as asking for it to be rewritten: a reader that reads and writes should not change bytes it was not asked to change.

Default: entities are already canonical. Override where two spellings of a member mean the same -- a rectilinear dimension's run-length encoding, a typesize that noshuffle ignores -- and where a contained entity has its own canonical form.

Source code in src/zarr_metadata/v3/_entity.py
def canonical(self) -> Self:
    """This entity in the simplest form that means the same thing.

    A *transformation*, asked for by `canonicalize_array_metadata_v3`
    and by nothing else. `to_json` does not apply it, because writing
    a document back is not the same as asking for it to be rewritten:
    a reader that reads and writes should not change bytes it was not
    asked to change.

    Default: entities are already canonical. Override where two
    spellings of a member mean the same -- a rectilinear dimension's
    run-length encoding, a `typesize` that `noshuffle` ignores -- and
    where a contained entity has its own canonical form.
    """
    return self

coerce classmethod

coerce(value: object, context: Context) -> Coerced[Self]

value as this entity, or the reasons it is not one.

context is the scope this reading is happening in; most entities have no use for it and ignore it.

Source code in src/zarr_metadata/v3/_entity.py
@classmethod
def coerce(cls, value: object, context: Context) -> Coerced[Self]:
    """`value` as this entity, or the reasons it is not one.

    `context` is the scope this reading is happening in; most entities
    have no use for it and ignore it.
    """
    name, configuration, must_understand = named_configuration(value)
    if name is None or not cls.accepts(name):
        return None, problem((), f"expected the {cls.identifier!r} entity")
    if configuration is None:
        if cls.configuration_required:
            return None, problem(
                ("configuration",),
                f"{cls.identifier!r} requires a configuration",
                "missing_key",
            )
        configuration = cast("Mapping[str, object]", {})
    members, found, unreadable = coerce_members(configuration, cls.member_types)
    if len(unreadable) != 0:
        # The entity cannot be built, but the members that *did* read
        # can still be judged -- one bad member should not hide the
        # value problems of the ones beside it. Anything the partial
        # reading says about an unreadable member is its default
        # talking, so those are dropped.
        partial = cls(must_understand=must_understand, **members)  # type: ignore[arg-type]
        found = (
            *found,
            # `within`, because a partial reading reports relative to
            # the configuration and `coerce`'s caller does not insert
            # that segment -- `coerce_members` problems already carry it.
            *within(
                (),
                [
                    entry
                    for entry in partial.problems()
                    if entry.loc[:1] not in {(key,) for key in unreadable}
                ],
            ),
        )
        return None, found
    return cls(must_understand=must_understand, **members), found  # type: ignore[arg-type]

configuration

configuration() -> dict[str, object]

This entity's configuration, as the document would write it.

Faithful to every member the entity holds: to_json is serialization, not canonicalization, so nothing is simplified here. Override only to render a member that is not already JSON, such as a contained entity.

Absent optional members are left out, which is what makes the bare-name spelling reachable. Absence is UNSET, never None: this package holds None to mean a JSON null the document actually wrote, and scale_offset is a real case where null and absent are different documents.

Source code in src/zarr_metadata/v3/_entity.py
def configuration(self) -> dict[str, object]:
    """This entity's configuration, as the document would write it.

    Faithful to every member the entity holds: `to_json` is
    serialization, not canonicalization, so nothing is simplified
    here. Override only to render a member that is not already JSON,
    such as a contained entity.

    Absent optional members are left out, which is what makes the
    bare-name spelling reachable. Absence is `UNSET`, never `None`:
    this package holds `None` to mean a JSON `null` the document
    actually wrote, and `scale_offset` is a real case where `null`
    and absent are different documents.
    """
    return {
        key: value
        for key in type(self).member_types
        if (value := getattr(self, key)) is not UNSET
    }

problems

problems() -> tuple[ValidationProblem, ...]

Every value of this entity the spec disallows.

Locations are relative to the entity's configuration. Default: an entity whose type admits only valid values has nothing to add.

Source code in src/zarr_metadata/v3/_entity.py
def problems(self) -> tuple[ValidationProblem, ...]:
    """Every value of this entity the spec disallows.

    Locations are relative to the entity's `configuration`. Default:
    an entity whose type admits only valid values has nothing to add.
    """
    return ()

to_json

This entity as a document would write it.

Faithful to every member: read a document, write it back, and the members come out as they went in. Ask canonical first if you want the simplest equivalent spelling.

What is not preserved is the envelope's spelling, because the entity does not model it: a bare name, {"name": x}, and {"name": x, "configuration": {}} all mean the same and all read to the same entity, so all three write back as the bare name. must_understand is omitted when true, which is its default; an explicit false is kept, because that one says something.

Subclasses narrow the return type to their own object TypedDict, which is the JSON form this dataclass models.

Source code in src/zarr_metadata/v3/chunk_key_encoding/v2.py
def to_json(self) -> V2ChunkKeyEncodingObject | V2ChunkKeyEncodingName:
    return cast("V2ChunkKeyEncodingObject | V2ChunkKeyEncodingName", super().to_json())

V2ChunkKeyEncodingConfiguration

Bases: TypedDict

Configuration for the v2 chunk key encoding.

separator is optional and defaults to "." per spec. https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/chunk-key-encodings/v2/index.rst#L27-L29

Source code in src/zarr_metadata/v3/chunk_key_encoding/v2.py
class V2ChunkKeyEncodingConfiguration(TypedDict, closed=True):
    """Configuration for the v2 chunk key encoding.

    `separator` is optional and defaults to `"."` per spec.
      https://github.com/zarr-developers/zarr-specs/blob/fc7dd9c9beb5a50b87f9b08b00bf50fc0048482f/docs/v3/chunk-key-encodings/v2/index.rst#L27-L29
    """

    separator: NotRequired[V2ChunkKeyEncodingSeparator]

separator instance-attribute

V2ChunkKeyEncodingObject

Bases: TypedDict

v2-compatibility chunk key encoding metadata in object form.

Source code in src/zarr_metadata/v3/chunk_key_encoding/v2.py
class V2ChunkKeyEncodingObject(TypedDict, closed=True):
    """v2-compatibility chunk key encoding metadata in object form."""

    name: V2ChunkKeyEncodingName
    configuration: NotRequired[V2ChunkKeyEncodingConfiguration]
    must_understand: NotRequired[bool]

configuration instance-attribute

must_understand instance-attribute

must_understand: NotRequired[bool]

name instance-attribute