Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/zarr/abc/serializable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import Protocol, Self, TypeVar

T_co = TypeVar("T_co", covariant=True)
T_contra = TypeVar("T_contra", contravariant=True)


class JSONSerializable(Protocol[T_co, T_contra]):
@classmethod
def from_json(cls, obj: T_contra) -> Self:
"""
Deserialize from an instance of T_contra.
"""
...

@classmethod
def try_from_json(cls, obj: object) -> Self:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def try_from_json(cls, obj: object) -> Self:
def from_object(cls, obj: object) -> Self:

as discussed on zulip, I'm don't find try_from_json to be intuitive

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I'm a fan of from_object, because the term "object" is unfortunately overloaded in python. People might think "object" means "a class instance" as opposed to "the base type object". I'd like to get a range of opinions here. cc @zarr-developers/python-core-devs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from_json_checked could convey that there's a type checking step...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we require typed input for now and add the untyped method later if there's demand?

from_json_checked could convey that there's a type checking step...

I think it could also mean that it's from a checked json. what about from_untyped_json or from_untyped?

"""
Deserialize from an unknown object. Details of any
deserialization failure should be conveyed via an exception.
"""
...

def to_json(self) -> T_co:
"""
Serialize to JSON.
"""
...
4 changes: 2 additions & 2 deletions src/zarr/api/asynchronous.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from zarr.core.common import (
JSON,
AccessModeLiteral,
DimensionNames,
DimensionNamesLike,
MemoryOrder,
ZarrFormat,
_default_zarr_format,
Expand Down Expand Up @@ -914,7 +914,7 @@ async def create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
config: ArrayConfigLike | None = None,
**kwargs: Any,
Expand Down
8 changes: 4 additions & 4 deletions src/zarr/api/synchronous.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from zarr.core.common import (
JSON,
AccessModeLiteral,
DimensionNames,
DimensionNamesLike,
MemoryOrder,
ShapeLike,
ZarrFormat,
Expand Down Expand Up @@ -649,7 +649,7 @@ def create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
config: ArrayConfigLike | None = None,
**kwargs: Any,
Expand Down Expand Up @@ -832,7 +832,7 @@ def create_array(
zarr_format: ZarrFormat | None = 3,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
Expand Down Expand Up @@ -1003,7 +1003,7 @@ def from_array(
zarr_format: ZarrFormat | None = None,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
Expand Down
30 changes: 15 additions & 15 deletions src/zarr/core/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
ZARR_JSON,
ZARRAY_JSON,
ZATTRS_JSON,
DimensionNames,
DimensionNamesLike,
MemoryOrder,
ShapeLike,
ZarrFormat,
Expand Down Expand Up @@ -389,7 +389,7 @@ async def create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
# runtime
overwrite: bool = False,
data: npt.ArrayLike | None = None,
Expand Down Expand Up @@ -417,7 +417,7 @@ async def create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
# runtime
overwrite: bool = False,
data: npt.ArrayLike | None = None,
Expand Down Expand Up @@ -445,7 +445,7 @@ async def create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
# v2 only
chunks: ShapeLike | None = None,
dimension_separator: Literal[".", "/"] | None = None,
Expand Down Expand Up @@ -479,7 +479,7 @@ async def create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
# v2 only
chunks: ShapeLike | None = None,
dimension_separator: Literal[".", "/"] | None = None,
Expand Down Expand Up @@ -630,7 +630,7 @@ async def _create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
# v2 only
chunks: ShapeLike | None = None,
dimension_separator: Literal[".", "/"] | None = None,
Expand Down Expand Up @@ -742,7 +742,7 @@ def _create_metadata_v3(
fill_value: Any | None = DEFAULT_FILL_VALUE,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
attributes: dict[str, JSON] | None = None,
) -> ArrayV3Metadata:
"""
Expand Down Expand Up @@ -803,7 +803,7 @@ async def _create_v3(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
attributes: dict[str, JSON] | None = None,
overwrite: bool = False,
) -> AsyncArrayV3:
Expand Down Expand Up @@ -1998,7 +1998,7 @@ def create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
# v2 only
chunks: tuple[int, ...] | None = None,
dimension_separator: Literal[".", "/"] | None = None,
Expand Down Expand Up @@ -2142,7 +2142,7 @@ def _create(
| None
) = None,
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
# v2 only
chunks: tuple[int, ...] | None = None,
dimension_separator: Literal[".", "/"] | None = None,
Expand Down Expand Up @@ -4266,7 +4266,7 @@ async def from_array(
zarr_format: ZarrFormat | None = None,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
Expand Down Expand Up @@ -4535,7 +4535,7 @@ async def init_array(
zarr_format: ZarrFormat | None = 3,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
) -> AnyAsyncArray:
Expand Down Expand Up @@ -4751,7 +4751,7 @@ async def create_array(
zarr_format: ZarrFormat | None = 3,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
Expand Down Expand Up @@ -4935,7 +4935,7 @@ def _parse_keep_array_attr(
order: MemoryOrder | None,
zarr_format: ZarrFormat | None,
chunk_key_encoding: ChunkKeyEncodingLike | None,
dimension_names: DimensionNames,
dimension_names: DimensionNamesLike,
) -> tuple[
tuple[int, ...] | Literal["auto"],
ShardsLike | None,
Expand All @@ -4946,7 +4946,7 @@ def _parse_keep_array_attr(
MemoryOrder | None,
ZarrFormat,
ChunkKeyEncodingLike | None,
DimensionNames,
DimensionNamesLike,
]:
if isinstance(data, Array):
if chunks == "keep":
Expand Down
6 changes: 4 additions & 2 deletions src/zarr/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
Generic,
Literal,
NotRequired,
TypeAlias,
TypedDict,
TypeVar,
cast,
Expand Down Expand Up @@ -43,11 +44,12 @@
ChunkCoords = tuple[int, ...]
ZarrFormat = Literal[2, 3]
NodeType = Literal["array", "group"]
JSON = str | int | float | bool | Mapping[str, "JSON"] | Sequence["JSON"] | None
JSON: TypeAlias = str | int | float | bool | Mapping[str, "JSON"] | Sequence["JSON"] | None
MemoryOrder = Literal["C", "F"]
AccessModeLiteral = Literal["r", "r+", "a", "w", "w-"]
ANY_ACCESS_MODE: Final = "r", "r+", "a", "w", "w-"
DimensionNames = Iterable[str | None] | None
DimensionNamesLike = Iterable[str | None] | None
DimensionNames = DimensionNamesLike # backwards compatibility

TName = TypeVar("TName", bound=str)
TConfig = TypeVar("TConfig", bound=Mapping[str, object])
Expand Down
10 changes: 5 additions & 5 deletions src/zarr/core/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
ZATTRS_JSON,
ZGROUP_JSON,
ZMETADATA_V2_JSON,
DimensionNames,
DimensionNamesLike,
NodeType,
ShapeLike,
ZarrFormat,
Expand Down Expand Up @@ -1032,7 +1032,7 @@ async def create_array(
order: MemoryOrder | None = None,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
Expand Down Expand Up @@ -2483,7 +2483,7 @@ def create(
order: MemoryOrder | None = None,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
Expand Down Expand Up @@ -2627,7 +2627,7 @@ def create_array(
order: MemoryOrder | None = None,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
Expand Down Expand Up @@ -3025,7 +3025,7 @@ def array(
order: MemoryOrder | None = None,
attributes: dict[str, JSON] | None = None,
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
dimension_names: DimensionNames = None,
dimension_names: DimensionNamesLike = None,
storage_options: dict[str, Any] | None = None,
overwrite: bool = False,
config: ArrayConfigLike | None = None,
Expand Down
8 changes: 5 additions & 3 deletions src/zarr/core/metadata/common.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from __future__ import annotations

from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from collections.abc import Mapping

from zarr.core.common import JSON


def parse_attributes(data: dict[str, JSON] | None) -> dict[str, JSON]:
def parse_attributes(data: Mapping[str, Any] | None) -> dict[str, JSON]:
if data is None:
return {}

return data
return dict(data)
Loading