Skip to content

Commit ad25833

Browse files
Check if zarr store supports consolidated metadata (#10457)
* new blank whatsnew * add test for store which explicitly does not support consolidated metadata * check for consolidated metadata support * WrapperStore now only imported and used if zarr v3 * use dedicated decorator * use getattr in case property not defined * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * implement with_read_only * change test to not expect warning if consolidated metadata not supported * move store definition outside of test * try setting Store=None when zarr-python v3 not installed * remove Store type hint entirely to avoid import issues * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * try WrapperStore = object * ensure WrapperStore is defined as something even if zarr isn't present at all * release note * correct RST syntax --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 0a4b378 commit ad25833

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ New Features
1414
~~~~~~~~~~~~
1515
- Expose :py:class:`~xarray.indexes.RangeIndex`, and :py:class:`~xarray.indexes.CoordinateTransformIndex` as public api
1616
under the ``xarray.indexes`` namespace. By `Deepak Cherian <https://github.com/dcherian>`_.
17+
- Support zarr-python's new ``.supports_consolidated_metadata`` store property (:pull:`10457``).
18+
by Tom Nicholas <https://github.com/TomNicholas>`_.
1719
- Better error messages when encoding data to be written to disk fails (:pull:`10464`).
1820
By `Stephan Hoyer <https://github.com/shoyer>`_
1921

xarray/backends/zarr.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,11 @@ def _get_open_params(
17681768
else:
17691769
missing_exc = zarr.errors.GroupNotFoundError
17701770

1771+
if _zarr_v3():
1772+
# zarr 3.0.8 and earlier did not support this property - it was effectively assumed true
1773+
if not getattr(store, "supports_consolidated_metadata", True):
1774+
consolidated = consolidate_on_close = False
1775+
17711776
if consolidated in [None, True]:
17721777
# open the root of the store, in case there is metadata consolidated there
17731778
group = open_kwargs.pop("path")
@@ -1825,6 +1830,7 @@ def _get_open_params(
18251830
else:
18261831
# this was the default for v2 and should apply to most existing Zarr data
18271832
use_zarr_fill_value_as_mask = True
1833+
18281834
return (
18291835
zarr_group,
18301836
consolidate_on_close,

xarray/tests/test_backends.py

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
requires_scipy,
9090
requires_scipy_or_netCDF4,
9191
requires_zarr,
92+
requires_zarr_v3,
9293
)
9394
from xarray.tests.test_coding_times import (
9495
_ALL_CALENDARS,
@@ -117,6 +118,7 @@
117118

118119
if has_zarr_v3:
119120
from zarr.storage import MemoryStore as KVStore
121+
from zarr.storage import WrapperStore
120122

121123
ZARR_FORMATS = [2, 3]
122124
else:
@@ -127,8 +129,11 @@
127129
)
128130
except ImportError:
129131
KVStore = None # type: ignore[assignment,misc,unused-ignore]
132+
133+
WrapperStore = object # type: ignore[assignment,misc,unused-ignore]
130134
else:
131135
KVStore = None # type: ignore[assignment,misc,unused-ignore]
136+
WrapperStore = object # type: ignore[assignment,misc,unused-ignore]
132137
ZARR_FORMATS = []
133138

134139

@@ -2400,12 +2405,13 @@ def test_read_non_consolidated_warning(self) -> None:
24002405
self.save(
24012406
expected, store_target=store, consolidated=False, **self.version_kwargs
24022407
)
2403-
with pytest.warns(
2404-
RuntimeWarning,
2405-
match="Failed to open Zarr store with consolidated",
2406-
):
2407-
with xr.open_zarr(store, **self.version_kwargs) as ds:
2408-
assert_identical(ds, expected)
2408+
if getattr(store, "supports_consolidated_metadata", True):
2409+
with pytest.warns(
2410+
RuntimeWarning,
2411+
match="Failed to open Zarr store with consolidated",
2412+
):
2413+
with xr.open_zarr(store, **self.version_kwargs) as ds:
2414+
assert_identical(ds, expected)
24092415

24102416
def test_non_existent_store(self) -> None:
24112417
with pytest.raises(
@@ -3756,6 +3762,42 @@ def test_chunk_key_encoding_v2(self) -> None:
37563762
assert actual["var1"].encoding["chunks"] == (2, 2)
37573763

37583764

3765+
class NoConsolidatedMetadataSupportStore(WrapperStore):
3766+
"""
3767+
Store that explicitly does not support consolidated metadata.
3768+
3769+
Useful as a proxy for stores like Icechunk, see https://github.com/zarr-developers/zarr-python/pull/3119.
3770+
"""
3771+
3772+
supports_consolidated_metadata = False
3773+
3774+
def __init__(
3775+
self,
3776+
store,
3777+
*,
3778+
read_only: bool = False,
3779+
) -> None:
3780+
self._store = store.with_read_only(read_only=read_only)
3781+
3782+
def with_read_only(
3783+
self, read_only: bool = False
3784+
) -> NoConsolidatedMetadataSupportStore:
3785+
return type(self)(
3786+
store=self._store,
3787+
read_only=read_only,
3788+
)
3789+
3790+
3791+
@requires_zarr_v3
3792+
class TestZarrNoConsolidatedMetadataSupport(ZarrBase):
3793+
@contextlib.contextmanager
3794+
def create_zarr_target(self):
3795+
# TODO the zarr version would need to be >3.08 for the supports_consolidated_metadata property to have any effect
3796+
yield NoConsolidatedMetadataSupportStore(
3797+
zarr.storage.MemoryStore({}, read_only=False)
3798+
)
3799+
3800+
37593801
@requires_zarr
37603802
@pytest.mark.skipif(
37613803
ON_WINDOWS,

0 commit comments

Comments
 (0)