Skip to content

Commit 76c3450

Browse files
d-v-bnormanrz
andauthored
Remove attrs (#1660)
* begin removing attrs in favor of frozen dataclasses * remove runtime_configuration from corearraymetadata; rename CodecMetadata to NamedConfig; turn chunk encoding into stand-alone functions; put codecs on ArrayMetadata instead of just CodecMetadata; add runtime_configuration parameter to codec encode / decode methods; add parsers to codecs * add typing_extensions dependency * remove CodecMetadatas and data_types; move basic parsers to common * feat: base to_dict method that actually works * Making Codec classes self-contained * fixes * chunk_grids * chunk key encodings * dry-er parse_* * serialize to enums * ruff * organize imports * rm src/zarr/v3/codecs/common.py * cleanup error messages * better codec evolve * __init__ types * add validation to RuntimeConfiguration.__init__; create a validator for c / f order; add order to ArrayV2Metadata.__init__ * import Dict at runtime * fix parse_dimension_names * add tests; tweak parse_name function; adjust some exception messages * fix shapelike parser and tests; clean up imports * typing * improve typing * blacken test_common --------- Co-authored-by: Norman Rzepka <code@normanrz.com>
1 parent c578963 commit 76c3450

27 files changed

+1812
-1243
lines changed

pyproject.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,12 @@ extra-dependencies = [
9292
"coverage",
9393
"pytest",
9494
"pytest-cov",
95+
"msgpack",
96+
"lmdb",
97+
"zstandard",
98+
"crc32c",
9599
"pytest-asyncio",
96-
"mypy",
100+
"typing_extensions"
97101
]
98102
features = ["extra"]
99103

src/zarr/v3/__init__.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
from typing import Union
44

55
import zarr.v3.codecs # noqa: F401
6-
from zarr.v3.array import Array # noqa: F401
7-
from zarr.v3.array_v2 import ArrayV2 # noqa: F401
8-
from zarr.v3.group import Group # noqa: F401
9-
from zarr.v3.metadata import RuntimeConfiguration, runtime_configuration # noqa: F401
6+
from zarr.v3.array import Array, AsyncArray # noqa: F401
7+
from zarr.v3.array_v2 import ArrayV2
8+
from zarr.v3.config import RuntimeConfiguration # noqa: F401
9+
from zarr.v3.group import AsyncGroup, Group # noqa: F401
10+
from zarr.v3.metadata import runtime_configuration # noqa: F401
1011
from zarr.v3.store import ( # noqa: F401
1112
StoreLike,
1213
make_store_path,
@@ -17,19 +18,24 @@
1718
async def open_auto_async(
1819
store: StoreLike,
1920
runtime_configuration_: RuntimeConfiguration = RuntimeConfiguration(),
20-
) -> Union[Array, ArrayV2, Group]:
21+
) -> Union[AsyncArray, AsyncGroup]:
2122
store_path = make_store_path(store)
2223
try:
23-
return await Array.open(store_path, runtime_configuration=runtime_configuration_)
24+
return await AsyncArray.open(store_path, runtime_configuration=runtime_configuration_)
2425
except KeyError:
25-
return await Group.open(store_path, runtime_configuration=runtime_configuration_)
26+
return await AsyncGroup.open(store_path, runtime_configuration=runtime_configuration_)
2627

2728

2829
def open_auto(
2930
store: StoreLike,
3031
runtime_configuration_: RuntimeConfiguration = RuntimeConfiguration(),
3132
) -> Union[Array, ArrayV2, Group]:
32-
return _sync(
33+
object = _sync(
3334
open_auto_async(store, runtime_configuration_),
3435
runtime_configuration_.asyncio_loop,
3536
)
37+
if isinstance(object, AsyncArray):
38+
return Array(object)
39+
if isinstance(object, AsyncGroup):
40+
return Group(object)
41+
raise TypeError(f"Unexpected object type. Got {type(object)}.")

src/zarr/v3/abc/codec.py

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,33 @@
11
from __future__ import annotations
22

3-
from abc import abstractmethod, ABC
4-
from typing import TYPE_CHECKING, Optional, Type
3+
from abc import abstractmethod
4+
from typing import TYPE_CHECKING, Optional
55

66
import numpy as np
7+
from zarr.v3.abc.metadata import Metadata
78

8-
from zarr.v3.common import BytesLike, SliceSelection
9+
from zarr.v3.common import ArraySpec
910
from zarr.v3.store import StorePath
1011

1112

1213
if TYPE_CHECKING:
13-
from zarr.v3.metadata import (
14-
ArraySpec,
15-
ArrayMetadata,
16-
DataType,
17-
CodecMetadata,
18-
RuntimeConfiguration,
19-
)
14+
from typing_extensions import Self
15+
from zarr.v3.common import BytesLike, SliceSelection
16+
from zarr.v3.metadata import ArrayMetadata
17+
from zarr.v3.config import RuntimeConfiguration
2018

2119

22-
class Codec(ABC):
20+
class Codec(Metadata):
2321
is_fixed_size: bool
2422

25-
@classmethod
26-
@abstractmethod
27-
def get_metadata_class(cls) -> Type[CodecMetadata]:
28-
pass
29-
30-
@classmethod
31-
@abstractmethod
32-
def from_metadata(cls, codec_metadata: CodecMetadata) -> Codec:
33-
pass
34-
3523
@abstractmethod
3624
def compute_encoded_size(self, input_byte_length: int, chunk_spec: ArraySpec) -> int:
3725
pass
3826

3927
def resolve_metadata(self, chunk_spec: ArraySpec) -> ArraySpec:
4028
return chunk_spec
4129

42-
def evolve(self, *, ndim: int, data_type: DataType) -> Codec:
30+
def evolve(self, array_spec: ArraySpec) -> Self:
4331
return self
4432

4533
def validate(self, array_metadata: ArrayMetadata) -> None:

src/zarr/v3/abc/metadata.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from __future__ import annotations
2+
from typing import TYPE_CHECKING, Sequence
3+
4+
if TYPE_CHECKING:
5+
from typing import Dict
6+
from typing_extensions import Self
7+
8+
from dataclasses import fields
9+
10+
from zarr.v3.common import JSON
11+
12+
13+
class Metadata:
14+
def to_dict(self) -> JSON:
15+
"""
16+
Recursively serialize this model to a dictionary.
17+
This method inspects the fields of self and calls `x.to_dict()` for any fields that
18+
are instances of `Metadata`. Sequences of `Metadata` are similarly recursed into, and
19+
the output of that recursion is collected in a list.
20+
"""
21+
...
22+
out_dict = {}
23+
for field in fields(self):
24+
key = field.name
25+
value = getattr(self, key)
26+
if isinstance(value, Metadata):
27+
out_dict[field.name] = getattr(self, field.name).to_dict()
28+
elif isinstance(value, str):
29+
out_dict[key] = value
30+
elif isinstance(value, Sequence):
31+
out_dict[key] = [v.to_dict() if isinstance(v, Metadata) else v for v in value]
32+
else:
33+
out_dict[key] = value
34+
35+
return out_dict
36+
37+
@classmethod
38+
def from_dict(cls, data: Dict[str, JSON]) -> Self:
39+
"""
40+
Create an instance of the model from a dictionary
41+
"""
42+
...
43+
44+
return cls(**data)

0 commit comments

Comments
 (0)