diff --git a/changes/4029.bugfix.md b/changes/4029.bugfix.md new file mode 100644 index 0000000000..f25add6b39 --- /dev/null +++ b/changes/4029.bugfix.md @@ -0,0 +1 @@ +Removed `VerboseModule` from `zarr.storage` so that the module can be serialized by `cloudpickle`, fixing compatibility with `dask.distributed`. Also removed the associated deprecation handling for `zarr.storage.default_compressor` and deprecated config keys. diff --git a/pyproject.toml b/pyproject.toml index 6a7238ff8f..930fea9040 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,6 +94,7 @@ homepage = "https://github.com/zarr-developers/zarr-python" # pins deliberately, e.g. via dependabot or `uv lock --upgrade`. [dependency-groups] test = [ + "cloudpickle==3.1.2", "coverage==7.14.1", "pytest==9.0.3", "pytest-asyncio==1.4.0", diff --git a/src/zarr/core/config.py b/src/zarr/core/config.py index 08d2a50ace..2e2191b28e 100644 --- a/src/zarr/core/config.py +++ b/src/zarr/core/config.py @@ -68,25 +68,6 @@ def enable_gpu(self) -> ConfigSet: ) -# these keys were removed from the config as part of the 3.1.0 release. -# these deprecations should be removed in 3.1.1 or thereabouts. -deprecations = { - "array.v2_default_compressor.numeric": None, - "array.v2_default_compressor.string": None, - "array.v2_default_compressor.bytes": None, - "array.v2_default_filters.string": None, - "array.v2_default_filters.bytes": None, - "array.v3_default_filters.numeric": None, - "array.v3_default_filters.raw": None, - "array.v3_default_filters.bytes": None, - "array.v3_default_serializer.numeric": None, - "array.v3_default_serializer.string": None, - "array.v3_default_serializer.bytes": None, - "array.v3_default_compressors.string": None, - "array.v3_default_compressors.bytes": None, - "array.v3_default_compressors": None, -} - # The default configuration for zarr config = Config( "zarr", @@ -146,7 +127,6 @@ def enable_gpu(self) -> ConfigSet: "ndbuffer": "zarr.buffer.cpu.NDBuffer", } ], - deprecations=deprecations, ) diff --git a/src/zarr/storage/__init__.py b/src/zarr/storage/__init__.py index f1bd1724af..1c41082ba7 100644 --- a/src/zarr/storage/__init__.py +++ b/src/zarr/storage/__init__.py @@ -1,9 +1,3 @@ -import sys -import warnings -from types import ModuleType -from typing import Any - -from zarr.errors import ZarrDeprecationWarning from zarr.storage._common import StoreLike, StorePath from zarr.storage._fsspec import FsspecStore from zarr.storage._local import LocalStore @@ -26,20 +20,3 @@ "WrapperStore", "ZipStore", ] - - -class VerboseModule(ModuleType): - def __setattr__(self, attr: str, value: Any) -> None: - if attr == "default_compressor": - warnings.warn( - "setting zarr.storage.default_compressor is deprecated, use " - "zarr.config to configure array.v2_default_compressor " - "e.g. config.set({'codecs.zstd':'numcodecs.Zstd', 'array.v2_default_compressor.numeric': 'zstd'})", - ZarrDeprecationWarning, - stacklevel=1, - ) - else: - super().__setattr__(attr, value) - - -sys.modules[__name__].__class__ = VerboseModule diff --git a/tests/test_config.py b/tests/test_config.py index a758378dc7..caa69a8e8c 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -443,33 +443,3 @@ def test_config_read_missing_chunks_write_empty_chunks(store: Store) -> None: arr = zarr.open_array(store) arr[:] = 0 assert np.array_equal(arr[:], [0, 0, 0, 0]) - - -@pytest.mark.parametrize( - "key", - [ - "array.v2_default_compressor.numeric", - "array.v2_default_compressor.string", - "array.v2_default_compressor.bytes", - "array.v2_default_filters.string", - "array.v2_default_filters.bytes", - "array.v3_default_filters.numeric", - "array.v3_default_filters.raw", - "array.v3_default_filters.bytes", - "array.v3_default_serializer.numeric", - "array.v3_default_serializer.string", - "array.v3_default_serializer.bytes", - "array.v3_default_compressors.string", - "array.v3_default_compressors.bytes", - "array.v3_default_compressors", - ], -) -def test_deprecated_config(key: str) -> None: - """ - Test that a valuerror is raised when setting the default chunk encoding for a given - data type category - """ - - with pytest.raises(ValueError): - with zarr.config.set({key: "foo"}): - pass diff --git a/tests/test_v2.py b/tests/test_v2.py index 3a063ac509..8543fc3c72 100644 --- a/tests/test_v2.py +++ b/tests/test_v2.py @@ -20,7 +20,6 @@ from zarr.core.dtype.wrapper import ZDType from zarr.core.group import Group from zarr.core.sync import sync -from zarr.errors import ZarrDeprecationWarning from zarr.storage import MemoryStore, StorePath @@ -225,9 +224,23 @@ def test_v2_non_contiguous(numpy_order: Literal["C", "F"], zarr_order: Literal[" assert (sub_arr).flags.c_contiguous -def test_default_compressor_deprecation_warning() -> None: - with pytest.warns(ZarrDeprecationWarning, match="default_compressor is deprecated"): +def test_storage_module_is_picklable() -> None: + import cloudpickle + + # regression test for gh-4029 + # cloudpickle is used by dask.distributed and cannot serialize custom module + # classes like the old VerboseModule + assert cloudpickle.dumps(zarr.storage) + + +def test_default_compressor_no_longer_warns() -> None: + import warnings + + # VerboseModule removed in gh-4029 to make zarr.storage picklable + with warnings.catch_warnings(record=True) as record: + warnings.simplefilter("always") zarr.storage.default_compressor = "zarr.codecs.zstd.ZstdCodec()" # type: ignore[attr-defined] + assert not any("default_compressor is deprecated" in str(w.message) for w in record) @pytest.mark.parametrize("fill_value", [None, (b"", 0, 0.0)], ids=["no_fill", "fill"])