Skip to content

Commit 8bbf10f

Browse files
committed
clean up array config parsing, and modify init_array to create parent groups and return an asyncarray instead of metadata
1 parent 9a7aee5 commit 8bbf10f

File tree

4 files changed

+43
-44
lines changed

4 files changed

+43
-44
lines changed

src/zarr/api/asynchronous.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from typing_extensions import deprecated
1111

1212
from zarr.core.array import Array, AsyncArray, create_array, get_array_metadata
13-
from zarr.core.array_spec import ArrayConfig, ArrayConfigLike
13+
from zarr.core.array_spec import ArrayConfig, ArrayConfigLike, ArrayConfigParams
1414
from zarr.core.buffer import NDArrayLike
1515
from zarr.core.common import (
1616
JSON,
@@ -856,7 +856,7 @@ async def create(
856856
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
857857
dimension_names: Iterable[str] | None = None,
858858
storage_options: dict[str, Any] | None = None,
859-
config: ArrayConfig | ArrayConfigLike | None = None,
859+
config: ArrayConfigLike | None = None,
860860
**kwargs: Any,
861861
) -> AsyncArray[ArrayV2Metadata] | AsyncArray[ArrayV3Metadata]:
862862
"""Create an array.
@@ -1018,7 +1018,7 @@ async def create(
10181018
mode = "a"
10191019
store_path = await make_store_path(store, path=path, mode=mode, storage_options=storage_options)
10201020

1021-
config_dict: ArrayConfigLike = {}
1021+
config_dict: ArrayConfigParams = {}
10221022

10231023
if write_empty_chunks is not None:
10241024
if config is not None:

src/zarr/api/synchronous.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
SerializerLike,
2626
ShardsLike,
2727
)
28-
from zarr.core.array_spec import ArrayConfig, ArrayConfigLike
28+
from zarr.core.array_spec import ArrayConfigLike
2929
from zarr.core.buffer import NDArrayLike
3030
from zarr.core.chunk_key_encodings import ChunkKeyEncoding, ChunkKeyEncodingLike
3131
from zarr.core.common import (
@@ -625,7 +625,7 @@ def create(
625625
codecs: Iterable[Codec | dict[str, JSON]] | None = None,
626626
dimension_names: Iterable[str] | None = None,
627627
storage_options: dict[str, Any] | None = None,
628-
config: ArrayConfig | ArrayConfigLike | None = None,
628+
config: ArrayConfigLike | None = None,
629629
**kwargs: Any,
630630
) -> Array:
631631
"""Create an array.
@@ -695,7 +695,7 @@ def create(
695695
storage_options : dict
696696
If using an fsspec URL to create the store, these will be passed to
697697
the backend implementation. Ignored otherwise.
698-
config : ArrayConfig or ArrayConfigLike, optional
698+
config : ArrayConfigLike, optional
699699
Runtime configuration of the array. If provided, will override the
700700
default values from `zarr.config.array`.
701701
@@ -761,7 +761,7 @@ def create_array(
761761
dimension_names: Iterable[str] | None = None,
762762
storage_options: dict[str, Any] | None = None,
763763
overwrite: bool = False,
764-
config: ArrayConfig | ArrayConfigLike | None = None,
764+
config: ArrayConfigLike | None = None,
765765
) -> Array:
766766
"""Create an array.
767767
@@ -853,7 +853,7 @@ def create_array(
853853
Ignored otherwise.
854854
overwrite : bool, default False
855855
Whether to overwrite an array with the same name in the store, if one exists.
856-
config : ArrayConfig or ArrayConfigLike, optional
856+
config : ArrayConfigLike, optional
857857
Runtime configuration for the array.
858858
859859
Returns

src/zarr/core/array.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ class AsyncArray(Generic[T_ArrayMetadata]):
219219
The metadata of the array.
220220
store_path : StorePath
221221
The path to the Zarr store.
222-
config : ArrayConfig, optional
222+
config : ArrayConfigLike, optional
223223
The runtime configuration of the array, by default None.
224224
225225
Attributes
@@ -244,22 +244,22 @@ def __init__(
244244
self: AsyncArray[ArrayV2Metadata],
245245
metadata: ArrayV2Metadata | ArrayV2MetadataDict,
246246
store_path: StorePath,
247-
config: ArrayConfig | None = None,
247+
config: ArrayConfigLike | None = None,
248248
) -> None: ...
249249

250250
@overload
251251
def __init__(
252252
self: AsyncArray[ArrayV3Metadata],
253253
metadata: ArrayV3Metadata | ArrayV3MetadataDict,
254254
store_path: StorePath,
255-
config: ArrayConfig | None = None,
255+
config: ArrayConfigLike | None = None,
256256
) -> None: ...
257257

258258
def __init__(
259259
self,
260260
metadata: ArrayMetadata | ArrayMetadataDict,
261261
store_path: StorePath,
262-
config: ArrayConfig | None = None,
262+
config: ArrayConfigLike | None = None,
263263
) -> None:
264264
if isinstance(metadata, dict):
265265
zarr_format = metadata["zarr_format"]
@@ -273,12 +273,11 @@ def __init__(
273273
raise ValueError(f"Invalid zarr_format: {zarr_format}. Expected 2 or 3")
274274

275275
metadata_parsed = parse_array_metadata(metadata)
276-
277-
config = ArrayConfig.from_dict({}) if config is None else config
276+
config_parsed = parse_array_config(config)
278277

279278
object.__setattr__(self, "metadata", metadata_parsed)
280279
object.__setattr__(self, "store_path", store_path)
281-
object.__setattr__(self, "_config", config)
280+
object.__setattr__(self, "_config", config_parsed)
282281
object.__setattr__(self, "codec_pipeline", create_codec_pipeline(metadata=metadata_parsed))
283282

284283
# this overload defines the function signature when zarr_format is 2
@@ -302,7 +301,7 @@ async def create(
302301
# runtime
303302
overwrite: bool = False,
304303
data: npt.ArrayLike | None = None,
305-
config: ArrayConfig | ArrayConfigLike | None = None,
304+
config: ArrayConfigLike | None = None,
306305
) -> AsyncArray[ArrayV2Metadata]: ...
307306

308307
# this overload defines the function signature when zarr_format is 3
@@ -331,7 +330,7 @@ async def create(
331330
# runtime
332331
overwrite: bool = False,
333332
data: npt.ArrayLike | None = None,
334-
config: ArrayConfig | ArrayConfigLike | None = None,
333+
config: ArrayConfigLike | None = None,
335334
) -> AsyncArray[ArrayV3Metadata]: ...
336335

337336
@overload
@@ -359,7 +358,7 @@ async def create(
359358
# runtime
360359
overwrite: bool = False,
361360
data: npt.ArrayLike | None = None,
362-
config: ArrayConfig | ArrayConfigLike | None = None,
361+
config: ArrayConfigLike | None = None,
363362
) -> AsyncArray[ArrayV3Metadata]: ...
364363

365364
@overload
@@ -393,7 +392,7 @@ async def create(
393392
# runtime
394393
overwrite: bool = False,
395394
data: npt.ArrayLike | None = None,
396-
config: ArrayConfig | ArrayConfigLike | None = None,
395+
config: ArrayConfigLike | None = None,
397396
) -> AsyncArray[ArrayV3Metadata] | AsyncArray[ArrayV2Metadata]: ...
398397

399398
@classmethod
@@ -428,7 +427,7 @@ async def create(
428427
# runtime
429428
overwrite: bool = False,
430429
data: npt.ArrayLike | None = None,
431-
config: ArrayConfig | ArrayConfigLike | None = None,
430+
config: ArrayConfigLike | None = None,
432431
) -> AsyncArray[ArrayV2Metadata] | AsyncArray[ArrayV3Metadata]:
433432
"""Method to create a new asynchronous array instance.
434433
@@ -506,7 +505,7 @@ async def create(
506505
Whether to raise an error if the store already exists (default is False).
507506
data : npt.ArrayLike, optional
508507
The data to be inserted into the array (default is None).
509-
config : ArrayConfig or ArrayConfigLike, optional
508+
config : ArrayConfigLike, optional
510509
Runtime configuration for the array.
511510
512511
Returns
@@ -569,7 +568,7 @@ async def _create(
569568
# runtime
570569
overwrite: bool = False,
571570
data: npt.ArrayLike | None = None,
572-
config: ArrayConfig | ArrayConfigLike | None = None,
571+
config: ArrayConfigLike | None = None,
573572
) -> AsyncArray[ArrayV2Metadata] | AsyncArray[ArrayV3Metadata]:
574573
"""Method to create a new asynchronous array instance.
575574
See :func:`AsyncArray.create` for more details.
@@ -1741,7 +1740,7 @@ def create(
17411740
compressor: dict[str, JSON] | None = None,
17421741
# runtime
17431742
overwrite: bool = False,
1744-
config: ArrayConfig | ArrayConfigLike | None = None,
1743+
config: ArrayConfigLike | None = None,
17451744
) -> Array:
17461745
"""Creates a new Array instance from an initialized store.
17471746
@@ -1870,7 +1869,7 @@ def _create(
18701869
compressor: dict[str, JSON] | None = None,
18711870
# runtime
18721871
overwrite: bool = False,
1873-
config: ArrayConfig | ArrayConfigLike | None = None,
1872+
config: ArrayConfigLike | None = None,
18741873
) -> Array:
18751874
"""Creates a new Array instance from an initialized store.
18761875
See :func:`Array.create` for more details.
@@ -3810,7 +3809,8 @@ async def init_array(
38103809
chunk_key_encoding: ChunkKeyEncodingLike | None = None,
38113810
dimension_names: Iterable[str] | None = None,
38123811
overwrite: bool = False,
3813-
) -> ArrayV3Metadata | ArrayV2Metadata:
3812+
config: ArrayConfigLike | None,
3813+
) -> AsyncArray[ArrayV3Metadata] | AsyncArray[ArrayV2Metadata]:
38143814
"""Create and persist an array metadata document.
38153815
38163816
Parameters
@@ -3889,11 +3889,13 @@ async def init_array(
38893889
Zarr format 3 only. Zarr format 2 arrays should not use this parameter.
38903890
overwrite : bool, default False
38913891
Whether to overwrite an array with the same name in the store, if one exists.
3892+
config : ArrayConfigLike or None, optional
3893+
Configuration for this array.
38923894
38933895
Returns
38943896
-------
3895-
ArrayV3Metadata | ArrayV2Metadata
3896-
The array metadata document.
3897+
AsyncArray
3898+
The AsyncArray.
38973899
"""
38983900

38993901
if zarr_format is None:
@@ -3993,14 +3995,9 @@ async def init_array(
39933995
attributes=attributes,
39943996
)
39953997

3996-
# save the metadata to disk
3997-
# TODO: make this easier -- it should be a simple function call that takes a {key: buffer}
3998-
coros = (
3999-
(store_path / key).set(value)
4000-
for key, value in meta.to_buffer_dict(default_buffer_prototype()).items()
4001-
)
4002-
await gather(*coros)
4003-
return meta
3998+
arr = AsyncArray(metadata=meta, store_path=store_path, config=config)
3999+
await arr._save_metadata(meta, ensure_parents=True)
4000+
return arr
40044001

40054002

40064003
async def create_array(
@@ -4023,7 +4020,7 @@ async def create_array(
40234020
dimension_names: Iterable[str] | None = None,
40244021
storage_options: dict[str, Any] | None = None,
40254022
overwrite: bool = False,
4026-
config: ArrayConfig | ArrayConfigLike | None = None,
4023+
config: ArrayConfigLike | None = None,
40274024
write_data: bool = True,
40284025
) -> AsyncArray[ArrayV2Metadata] | AsyncArray[ArrayV3Metadata]:
40294026
"""Create an array.
@@ -4113,7 +4110,7 @@ async def create_array(
41134110
Ignored otherwise.
41144111
overwrite : bool, default False
41154112
Whether to overwrite an array with the same name in the store, if one exists.
4116-
config : ArrayConfig or ArrayConfigLike, optional
4113+
config : ArrayConfigLike, optional
41174114
Runtime configuration for the array.
41184115
write_data : bool
41194116
If a pre-existing array-like object was provided to this function via the ``data`` parameter
@@ -4139,13 +4136,12 @@ async def create_array(
41394136
<AsyncArray memory://140349042942400 shape=(100, 100) dtype=int32>
41404137
"""
41414138
mode: Literal["a"] = "a"
4142-
config_parsed = parse_array_config(config)
41434139
store_path = await make_store_path(store, path=name, mode=mode, storage_options=storage_options)
41444140

41454141
data_parsed, shape_parsed, dtype_parsed = _parse_data_params(
41464142
data=data, shape=shape, dtype=dtype
41474143
)
4148-
meta = await init_array(
4144+
result = await init_array(
41494145
store_path=store_path,
41504146
shape=shape_parsed,
41514147
dtype=dtype_parsed,
@@ -4161,9 +4157,9 @@ async def create_array(
41614157
chunk_key_encoding=chunk_key_encoding,
41624158
dimension_names=dimension_names,
41634159
overwrite=overwrite,
4160+
config=config,
41644161
)
41654162

4166-
result = AsyncArray(metadata=meta, store_path=store_path, config=config_parsed)
41674163
if write_data is True and data_parsed is not None:
41684164
await result._set_selection(
41694165
BasicIndexer(..., shape=result.shape, chunk_grid=result.metadata.chunk_grid),

src/zarr/core/array_spec.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from zarr.core.common import ChunkCoords
2222

2323

24-
class ArrayConfigLike(TypedDict):
24+
class ArrayConfigParams(TypedDict):
2525
"""
2626
A TypedDict model of the attributes of an ArrayConfig class, but with no required fields.
2727
This allows for partial construction of an ArrayConfig, with the assumption that the unset
@@ -56,13 +56,13 @@ def __init__(self, order: MemoryOrder, write_empty_chunks: bool) -> None:
5656
object.__setattr__(self, "write_empty_chunks", write_empty_chunks_parsed)
5757

5858
@classmethod
59-
def from_dict(cls, data: ArrayConfigLike) -> Self:
59+
def from_dict(cls, data: ArrayConfigParams) -> Self:
6060
"""
6161
Create an ArrayConfig from a dict. The keys of that dict are a subset of the
6262
attributes of the ArrayConfig class. Any keys missing from that dict will be set to the
6363
the values in the ``array`` namespace of ``zarr.config``.
6464
"""
65-
kwargs_out: ArrayConfigLike = {}
65+
kwargs_out: ArrayConfigParams = {}
6666
for f in fields(ArrayConfig):
6767
field_name = cast(Literal["order", "write_empty_chunks"], f.name)
6868
if field_name not in data:
@@ -72,7 +72,10 @@ def from_dict(cls, data: ArrayConfigLike) -> Self:
7272
return cls(**kwargs_out)
7373

7474

75-
def parse_array_config(data: ArrayConfig | ArrayConfigLike | None) -> ArrayConfig:
75+
ArrayConfigLike = ArrayConfig | ArrayConfigParams
76+
77+
78+
def parse_array_config(data: ArrayConfigLike | None) -> ArrayConfig:
7679
"""
7780
Convert various types of data to an ArrayConfig.
7881
"""

0 commit comments

Comments
 (0)