Skip to content

Commit 369a028

Browse files
d-v-bclaude
andcommitted
Merge branch 'main' into fix/strict-chunk-sizes
Resolves the import conflict in group.py with zarr-developers#4391: keep both import lines. Assisted-by: ClaudeCode:claude-fable-5-1 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2 parents 100040f + 9677081 commit 369a028

17 files changed

Lines changed: 568 additions & 232 deletions

File tree

‎changes/4391.bugfix.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Zarr format 3 group metadata now accepts extra fields that are objects with `"must_understand": false`, as the specification requires, and writes them back unchanged; previously opening such a group raised `TypeError`. Extra fields of any other shape raise `MetadataValidationError`, both when reading a metadata document and when constructing `GroupMetadata` or `ArrayV3Metadata` directly. `GroupMetadata` exposes these fields as `extra_fields`, like `ArrayV3Metadata`.

‎changes/4413.bugfix.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`Group.require_array` now applies the `config` argument when it returns an existing array. Previously `config` was only used when `require_array` created a new array, so an existing array was returned with the global defaults. An invalid `config` now raises instead of being ignored.

‎changes/4415.bugfix.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`zarr.save` now takes `storage_options` as an option instead of treating it as one of the arrays to save: saving a single array with `storage_options` set no longer produces a group holding `arr_0`, and the options now reach the store. `zarr.save_group` no longer fails with `'storage_options' was provided but unused` when the arrays are passed positionally.

‎changes/4417.misc.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix `test_docstring_consistent_parameters`, which silently passed because it looked up a tuple of parameter names as a single key and concatenated two names into one. The test now checks every parameter documented by the `create_array` variants (`zarr.create_array`, `AsyncGroup.create_array`, `Group.create_array` and `Group.create`), and their docstrings were aligned: `shape`, `dtype`, `data`, `chunks`, `chunk_key_encoding`, `config` and `overwrite` now document the same types and text, `AsyncGroup.create_array` documents `data`, and typos in the chunk key encoding examples, the variable-length data type list and the Zarr format 2 default compressor description are corrected.

‎changes/4452.bugfix.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixed `FsspecStore.list_dir` and `FsspecStore.list_prefix` returning nothing below the root of a store whose path is `""` or `"/"`, such as a store opened from `"reference://"`. Nested groups in kerchunk-style references now list their members.

‎src/zarr/api/asynchronous.py‎

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ async def save(
435435
*args: NDArrayLike,
436436
zarr_format: ZarrFormat | None = None,
437437
path: str | None = None,
438+
storage_options: dict[str, Any] | None = None,
438439
**kwargs: Any, # TODO: type kwargs as valid args to save
439440
) -> None:
440441
"""Convenience function to save an array or group of arrays to the local file system.
@@ -451,16 +452,28 @@ async def save(
451452
The zarr format to use when saving.
452453
path : str or None, optional
453454
The path within the group where the arrays will be saved.
455+
storage_options : dict
456+
If using an fsspec URL to create the store, these will be passed to
457+
the backend implementation. Ignored otherwise.
454458
**kwargs
455459
NumPy arrays with data to save.
456460
"""
457461

458462
if len(args) == 0 and len(kwargs) == 0:
459463
raise ValueError("at least one array must be provided")
460464
if len(args) == 1 and len(kwargs) == 0:
461-
await save_array(store, args[0], zarr_format=zarr_format, path=path)
465+
await save_array(
466+
store, args[0], zarr_format=zarr_format, path=path, storage_options=storage_options
467+
)
462468
else:
463-
await save_group(store, *args, zarr_format=zarr_format, path=path, **kwargs)
469+
await save_group(
470+
store,
471+
*args,
472+
zarr_format=zarr_format,
473+
path=path,
474+
storage_options=storage_options,
475+
**kwargs,
476+
)
464477

465478

466479
async def save_array(
@@ -566,16 +579,10 @@ async def save_group(
566579
if len(args) == 0 and len(kwargs) == 0:
567580
raise ValueError("at least one array must be provided")
568581
aws = []
582+
# `store_path` already consumed `storage_options`, so passing them on again would
583+
# make `make_store_path` reject them as unused.
569584
for i, arr in enumerate(args):
570-
aws.append(
571-
save_array(
572-
store_path,
573-
arr,
574-
zarr_format=zarr_format,
575-
path=f"arr_{i}",
576-
storage_options=storage_options,
577-
)
578-
)
585+
aws.append(save_array(store_path, arr, zarr_format=zarr_format, path=f"arr_{i}"))
579586
for k, arr in kwargs.items():
580587
aws.append(save_array(store_path, arr, zarr_format=zarr_format, path=k))
581588
await asyncio.gather(*aws)
@@ -974,7 +981,7 @@ async def create(
974981
type of the array and the Zarr format specified. For all data types in Zarr V3, and most
975982
data types in Zarr V2, the default filters are empty. The only cases where default filters
976983
are not empty is when the Zarr format is 2, and the data type is a variable-length data type like
977-
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthUTF8`][]. In these cases,
984+
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthBytes`][]. In these cases,
978985
the default filters contains a single element which is a codec specific to that particular data type.
979986
980987
To create an array with no filters, provide an empty iterable or the value `None`.

‎src/zarr/api/synchronous.py‎

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ def save(
259259
*args: NDArrayLike,
260260
zarr_format: ZarrFormat | None = None,
261261
path: str | None = None,
262+
storage_options: dict[str, Any] | None = None,
262263
**kwargs: Any, # TODO: type kwargs as valid args to async_api.save
263264
) -> None:
264265
"""Save an array or group of arrays to the local file system.
@@ -275,10 +276,22 @@ def save(
275276
The zarr format to use when saving.
276277
path : str or None, optional
277278
The path within the group where the arrays will be saved.
279+
storage_options : dict
280+
If using an fsspec URL to create the store, these will be passed to
281+
the backend implementation. Ignored otherwise.
278282
**kwargs
279283
NumPy arrays with data to save.
280284
"""
281-
return sync(async_api.save(store, *args, zarr_format=zarr_format, path=path, **kwargs))
285+
return sync(
286+
async_api.save(
287+
store,
288+
*args,
289+
zarr_format=zarr_format,
290+
path=path,
291+
storage_options=storage_options,
292+
**kwargs,
293+
)
294+
)
282295

283296

284297
def save_array(
@@ -712,7 +725,7 @@ def create(
712725
type of the array and the Zarr format specified. For all data types in Zarr V3, and most
713726
data types in Zarr V2, the default filters are empty. The only cases where default filters
714727
are not empty is when the Zarr format is 2, and the data type is a variable-length data type like
715-
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthUTF8`][]. In these cases,
728+
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthBytes`][]. In these cases,
716729
the default filters contains a single element which is a codec specific to that particular data type.
717730
718731
To create an array with no filters, provide an empty iterable or the value `None`.
@@ -872,7 +885,6 @@ def create_array(
872885
chunk to bytes.
873886
874887
For Zarr format 3, a "filter" is a codec that takes an array and returns an array,
875-
876888
and these values must be instances of [`zarr.abc.codec.ArrayArrayCodec`][], or a
877889
dict representations of [`zarr.abc.codec.ArrayArrayCodec`][].
878890
@@ -883,7 +895,7 @@ def create_array(
883895
type of the array and the Zarr format specified. For all data types in Zarr V3, and most
884896
data types in Zarr V2, the default filters are empty. The only cases where default filters
885897
are not empty is when the Zarr format is 2, and the data type is a variable-length data type like
886-
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthUTF8`][]. In these cases,
898+
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthBytes`][]. In these cases,
887899
the default filters contains a single element which is a codec specific to that particular data type.
888900
889901
To create an array with no filters, provide an empty iterable or the value `None`.
@@ -901,6 +913,7 @@ def create_array(
901913
For Zarr format 2, a "compressor" can be any numcodecs codec. Only a single compressor may
902914
be provided for Zarr format 2.
903915
If no `compressor` is provided, a default compressor will be used.
916+
This default can be changed by modifying the value of `array.v2_default_compressor`
904917
in [`zarr.config`][zarr.config].
905918
Use `None` to omit the default compressor.
906919
serializer : dict[str, JSON] | ArrayBytesCodec, optional
@@ -925,8 +938,8 @@ def create_array(
925938
Attributes for the array.
926939
chunk_key_encoding : ChunkKeyEncodingLike, optional
927940
A specification of how the chunk keys are represented in storage.
928-
For Zarr format 3, the default is `{"name": "default", "separator": "/"}}`.
929-
For Zarr format 2, the default is `{"name": "v2", "separator": "."}}`.
941+
For Zarr format 3, the default is `{"name": "default", "separator": "/"}`.
942+
For Zarr format 2, the default is `{"name": "v2", "separator": "."}`.
930943
dimension_names : Iterable[str], optional
931944
The names of the dimensions (default is None).
932945
Zarr format 3 only. Zarr format 2 arrays should not use this parameter.
@@ -935,7 +948,7 @@ def create_array(
935948
Ignored otherwise.
936949
overwrite : bool, default False
937950
Whether to overwrite an array with the same name in the store, if one exists.
938-
If `True`, all existing paths in the store will be deleted.
951+
If `True`, any existing keys under that path are deleted first.
939952
config : ArrayConfigLike, optional
940953
Runtime configuration for the array.
941954
write_data : bool
@@ -1126,8 +1139,8 @@ def from_array(
11261139
Pass an empty dict to create the array with no attributes.
11271140
chunk_key_encoding : ChunkKeyEncoding, optional
11281141
A specification of how the chunk keys are represented in storage.
1129-
For Zarr format 3, the default is `{"name": "default", "separator": "/"}}`.
1130-
For Zarr format 2, the default is `{"name": "v2", "separator": "."}}`.
1142+
For Zarr format 3, the default is `{"name": "default", "separator": "/"}`.
1143+
For Zarr format 2, the default is `{"name": "v2", "separator": "."}`.
11311144
If not specified and the data array has the same zarr format as the target array,
11321145
the chunk key encoding of the data array is used.
11331146
dimension_names : Iterable[str | None] | None

‎src/zarr/core/array.py‎

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4314,8 +4314,8 @@ async def from_array(
43144314
Pass an empty dict to create the array with no attributes.
43154315
chunk_key_encoding : ChunkKeyEncoding, optional
43164316
A specification of how the chunk keys are represented in storage.
4317-
For Zarr format 3, the default is `{"name": "default", "separator": "/"}}`.
4318-
For Zarr format 2, the default is `{"name": "v2", "separator": "."}}`.
4317+
For Zarr format 3, the default is `{"name": "default", "separator": "/"}`.
4318+
For Zarr format 2, the default is `{"name": "v2", "separator": "."}`.
43194319
If not specified and the data array has the same zarr format as the target array,
43204320
the chunk key encoding of the data array is used.
43214321
dimension_names : Iterable[str | None] | None
@@ -4512,7 +4512,7 @@ async def init_array(
45124512
type of the array and the Zarr format specified. For all data types in Zarr V3, and most
45134513
data types in Zarr V2, the default filters are empty. The only cases where default filters
45144514
are not empty is when the Zarr format is 2, and the data type is a variable-length data type like
4515-
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthUTF8`][]. In these cases,
4515+
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthBytes`][]. In these cases,
45164516
the default filters contains a single element which is a codec specific to that particular data type.
45174517
45184518
To create an array with no filters, provide an empty iterable or the value `None`.
@@ -4547,8 +4547,8 @@ async def init_array(
45474547
Attributes for the array.
45484548
chunk_key_encoding : ChunkKeyEncodingLike, optional
45494549
A specification of how the chunk keys are represented in storage.
4550-
For Zarr format 3, the default is `{"name": "default", "separator": "/"}}`.
4551-
For Zarr format 2, the default is `{"name": "v2", "separator": "."}}`.
4550+
For Zarr format 3, the default is `{"name": "default", "separator": "/"}`.
4551+
For Zarr format 2, the default is `{"name": "v2", "separator": "."}`.
45524552
dimension_names : Iterable[str], optional
45534553
The names of the dimensions (default is None).
45544554
Zarr format 3 only. Zarr format 2 arrays should not use this parameter.
@@ -4754,7 +4754,6 @@ async def create_array(
47544754
chunk to bytes.
47554755
47564756
For Zarr format 3, a "filter" is a codec that takes an array and returns an array,
4757-
47584757
and these values must be instances of [`zarr.abc.codec.ArrayArrayCodec`][], or a
47594758
dict representations of [`zarr.abc.codec.ArrayArrayCodec`][].
47604759
@@ -4765,7 +4764,7 @@ async def create_array(
47654764
type of the array and the Zarr format specified. For all data types in Zarr V3, and most
47664765
data types in Zarr V2, the default filters are empty. The only cases where default filters
47674766
are not empty is when the Zarr format is 2, and the data type is a variable-length data type like
4768-
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthUTF8`][]. In these cases,
4767+
[`zarr.dtype.VariableLengthUTF8`][] or [`zarr.dtype.VariableLengthBytes`][]. In these cases,
47694768
the default filters contains a single element which is a codec specific to that particular data type.
47704769
47714770
To create an array with no filters, provide an empty iterable or the value `None`.
@@ -4783,6 +4782,7 @@ async def create_array(
47834782
For Zarr format 2, a "compressor" can be any numcodecs codec. Only a single compressor may
47844783
be provided for Zarr format 2.
47854784
If no `compressor` is provided, a default compressor will be used.
4785+
This default can be changed by modifying the value of `array.v2_default_compressor`
47864786
in [`zarr.config`][zarr.config].
47874787
Use `None` to omit the default compressor.
47884788
serializer : dict[str, JSON] | ArrayBytesCodec, optional
@@ -4807,8 +4807,8 @@ async def create_array(
48074807
Attributes for the array.
48084808
chunk_key_encoding : ChunkKeyEncodingLike, optional
48094809
A specification of how the chunk keys are represented in storage.
4810-
For Zarr format 3, the default is `{"name": "default", "separator": "/"}}`.
4811-
For Zarr format 2, the default is `{"name": "v2", "separator": "."}}`.
4810+
For Zarr format 3, the default is `{"name": "default", "separator": "/"}`.
4811+
For Zarr format 2, the default is `{"name": "v2", "separator": "."}`.
48124812
dimension_names : Iterable[str], optional
48134813
The names of the dimensions (default is None).
48144814
Zarr format 3 only. Zarr format 2 arrays should not use this parameter.
@@ -4817,7 +4817,7 @@ async def create_array(
48174817
Ignored otherwise.
48184818
overwrite : bool, default False
48194819
Whether to overwrite an array with the same name in the store, if one exists.
4820-
If `True`, all existing paths in the store will be deleted.
4820+
If `True`, any existing keys under that path are deleted first.
48214821
config : ArrayConfigLike, optional
48224822
Runtime configuration for the array.
48234823
write_data : bool

0 commit comments

Comments
 (0)