diff --git a/pyproject.toml b/pyproject.toml index 6c18563a1f..f1e2525f50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -408,7 +408,7 @@ filterwarnings = [ "ignore:Automatic shard shape inference is experimental and may change without notice.*:UserWarning", "ignore:The codec .* is currently not part in the Zarr format 3 specification.*:UserWarning", "ignore:The dtype .* is currently not part in the Zarr format 3 specification.*:UserWarning", - "ignore:Use zarr.create_array instead.:DeprecationWarning", + "ignore:Use zarr.create_array instead.:zarr.errors.ZarrDeprecationWarning", "ignore:Duplicate name.*:UserWarning", "ignore:The `compressor` argument is deprecated. Use `compressors` instead.:UserWarning", "ignore:Numcodecs codecs are not in the Zarr version 3 specification and may not be supported by other zarr implementations.:UserWarning", diff --git a/src/zarr/_compat.py b/src/zarr/_compat.py index 52d96005cc..87427b486e 100644 --- a/src/zarr/_compat.py +++ b/src/zarr/_compat.py @@ -4,6 +4,8 @@ from inspect import Parameter, signature from typing import Any, TypeVar +from zarr.errors import ZarrFutureWarning + T = TypeVar("T") # Based off https://github.com/scikit-learn/scikit-learn/blob/e87b32a81c70abed8f2e97483758eb64df8255e9/sklearn/utils/validation.py#L63 @@ -54,7 +56,7 @@ def inner_f(*args: Any, **kwargs: Any) -> T: f"{version} passing these as positional arguments " "will result in an error" ), - FutureWarning, + ZarrFutureWarning, stacklevel=2, ) kwargs.update(zip(sig.parameters, args, strict=False)) diff --git a/src/zarr/api/asynchronous.py b/src/zarr/api/asynchronous.py index 3b53095636..4020dfc48f 100644 --- a/src/zarr/api/asynchronous.py +++ b/src/zarr/api/asynchronous.py @@ -40,7 +40,7 @@ create_hierarchy, ) from zarr.core.metadata import ArrayMetadataDict, ArrayV2Metadata, ArrayV3Metadata -from zarr.errors import GroupNotFoundError, NodeTypeValidationError +from zarr.errors import GroupNotFoundError, NodeTypeValidationError, ZarrDeprecationWarning from zarr.storage import StorePath from zarr.storage._common import make_store_path @@ -161,7 +161,7 @@ def _handle_zarr_version_or_format( ) if zarr_version is not None: warnings.warn( - "zarr_version is deprecated, use zarr_format", DeprecationWarning, stacklevel=2 + "zarr_version is deprecated, use zarr_format", ZarrDeprecationWarning, stacklevel=2 ) return zarr_version return zarr_format @@ -535,7 +535,7 @@ async def save_group( await asyncio.gather(*aws) -@deprecated("Use AsyncGroup.tree instead.") +@deprecated("Use AsyncGroup.tree instead.", category=ZarrDeprecationWarning) async def tree(grp: AsyncGroup, expand: bool | None = None, level: int | None = None) -> Any: """Provide a rich display of the hierarchy. diff --git a/src/zarr/api/synchronous.py b/src/zarr/api/synchronous.py index f2dc8757d6..4c698b51fa 100644 --- a/src/zarr/api/synchronous.py +++ b/src/zarr/api/synchronous.py @@ -11,6 +11,7 @@ from zarr.core.group import Group from zarr.core.sync import sync from zarr.core.sync_group import create_hierarchy +from zarr.errors import ZarrDeprecationWarning if TYPE_CHECKING: from collections.abc import Iterable @@ -341,7 +342,7 @@ def save_group( ) -@deprecated("Use Group.tree instead.") +@deprecated("Use Group.tree instead.", category=ZarrDeprecationWarning) def tree(grp: Group, expand: bool | None = None, level: int | None = None) -> Any: """Provide a rich display of the hierarchy. diff --git a/src/zarr/convenience.py b/src/zarr/convenience.py index 88f10663b7..3ca4ffcb4b 100644 --- a/src/zarr/convenience.py +++ b/src/zarr/convenience.py @@ -22,6 +22,7 @@ save_group, tree, ) +from zarr.errors import ZarrDeprecationWarning __all__ = [ "consolidate_metadata", @@ -40,6 +41,6 @@ warnings.warn( "zarr.convenience is deprecated. " "Import these functions from the top level zarr. namespace instead.", - DeprecationWarning, + ZarrDeprecationWarning, stacklevel=2, ) diff --git a/src/zarr/core/array.py b/src/zarr/core/array.py index cd6b33a28c..f79999842b 100644 --- a/src/zarr/core/array.py +++ b/src/zarr/core/array.py @@ -114,7 +114,7 @@ ) from zarr.core.metadata.v3 import parse_node_type_array from zarr.core.sync import sync -from zarr.errors import MetadataValidationError +from zarr.errors import MetadataValidationError, ZarrDeprecationWarning from zarr.registry import ( _parse_array_array_codec, _parse_array_bytes_codec, @@ -401,7 +401,7 @@ async def create( ) -> AsyncArray[ArrayV3Metadata] | AsyncArray[ArrayV2Metadata]: ... @classmethod - @deprecated("Use zarr.api.asynchronous.create_array instead.") + @deprecated("Use zarr.api.asynchronous.create_array instead.", category=ZarrDeprecationWarning) @_deprecate_positional_args async def create( cls, @@ -1009,7 +1009,7 @@ def serializer(self) -> ArrayBytesCodec | None: ) @property - @deprecated("Use AsyncArray.compressors instead.") + @deprecated("Use AsyncArray.compressors instead.", category=ZarrDeprecationWarning) def compressor(self) -> numcodecs.abc.Codec | None: """ Compressor that is applied to each chunk of the array. @@ -1740,7 +1740,7 @@ class Array: _async_array: AsyncArray[ArrayV3Metadata] | AsyncArray[ArrayV2Metadata] @classmethod - @deprecated("Use zarr.create_array instead.") + @deprecated("Use zarr.create_array instead.", category=ZarrDeprecationWarning) @_deprecate_positional_args def create( cls, @@ -2128,7 +2128,7 @@ def serializer(self) -> None | ArrayBytesCodec: return self._async_array.serializer @property - @deprecated("Use Array.compressors instead.") + @deprecated("Use Array.compressors instead.", category=ZarrDeprecationWarning) def compressor(self) -> numcodecs.abc.Codec | None: """ Compressor that is applied to each chunk of the array. diff --git a/src/zarr/core/dtype/common.py b/src/zarr/core/dtype/common.py index 6f61b6775e..ed7cf453e8 100644 --- a/src/zarr/core/dtype/common.py +++ b/src/zarr/core/dtype/common.py @@ -14,6 +14,7 @@ ) from zarr.core.common import NamedConfig +from zarr.errors import ZarrFutureWarning EndiannessStr = Literal["little", "big"] ENDIANNESS_STR: Final = "little", "big" @@ -205,7 +206,7 @@ class HasObjectCodec: object_codec_id: ClassVar[str] -class UnstableSpecificationWarning(FutureWarning): ... +class UnstableSpecificationWarning(ZarrFutureWarning): ... def v3_unstable_dtype_warning(dtype: object) -> None: diff --git a/src/zarr/core/group.py b/src/zarr/core/group.py index 4c8ced21f4..f3702b6891 100644 --- a/src/zarr/core/group.py +++ b/src/zarr/core/group.py @@ -50,7 +50,12 @@ from zarr.core.config import config from zarr.core.metadata import ArrayV2Metadata, ArrayV3Metadata from zarr.core.sync import SyncMixin, sync -from zarr.errors import ContainsArrayError, ContainsGroupError, MetadataValidationError +from zarr.errors import ( + ContainsArrayError, + ContainsGroupError, + MetadataValidationError, + ZarrDeprecationWarning, +) from zarr.storage import StoreLike, StorePath from zarr.storage._common import ensure_no_existing_node, make_store_path from zarr.storage._utils import _join_paths, _normalize_path_keys, normalize_path @@ -1132,7 +1137,7 @@ async def create_array( config=config, ) - @deprecated("Use AsyncGroup.create_array instead.") + @deprecated("Use AsyncGroup.create_array instead.", category=ZarrDeprecationWarning) async def create_dataset( self, name: str, *, shape: ShapeLike, **kwargs: Any ) -> AsyncArray[ArrayV2Metadata] | AsyncArray[ArrayV3Metadata]: @@ -1166,7 +1171,7 @@ async def create_dataset( await array.setitem(slice(None), data) return array - @deprecated("Use AsyncGroup.require_array instead.") + @deprecated("Use AsyncGroup.require_array instead.", category=ZarrDeprecationWarning) async def require_dataset( self, name: str, @@ -2545,7 +2550,7 @@ def create_array( ) ) - @deprecated("Use Group.create_array instead.") + @deprecated("Use Group.create_array instead.", category=ZarrDeprecationWarning) def create_dataset(self, name: str, **kwargs: Any) -> Array: """Create an array. @@ -2569,7 +2574,7 @@ def create_dataset(self, name: str, **kwargs: Any) -> Array: """ return Array(self._sync(self._async_group.create_dataset(name, **kwargs))) - @deprecated("Use Group.require_array instead.") + @deprecated("Use Group.require_array instead.", category=ZarrDeprecationWarning) def require_dataset(self, name: str, *, shape: ShapeLike, **kwargs: Any) -> Array: """Obtain an array, creating if it doesn't exist. @@ -2799,7 +2804,7 @@ def move(self, source: str, dest: str) -> None: """ return self._sync(self._async_group.move(source, dest)) - @deprecated("Use Group.create_array instead.") + @deprecated("Use Group.create_array instead.", category=ZarrDeprecationWarning) @_deprecate_positional_args def array( self, diff --git a/src/zarr/creation.py b/src/zarr/creation.py index 8197c4950c..622406ed75 100644 --- a/src/zarr/creation.py +++ b/src/zarr/creation.py @@ -23,6 +23,7 @@ zeros, zeros_like, ) +from zarr.errors import ZarrDeprecationWarning __all__ = [ "array", @@ -42,6 +43,6 @@ warnings.warn( "zarr.creation is deprecated. " "Import these functions from the top level zarr. namespace instead.", - DeprecationWarning, + ZarrDeprecationWarning, stacklevel=2, ) diff --git a/src/zarr/errors.py b/src/zarr/errors.py index 4f972a6703..fea18e7720 100644 --- a/src/zarr/errors.py +++ b/src/zarr/errors.py @@ -66,3 +66,9 @@ class NodeTypeValidationError(MetadataValidationError): This can be raised when the value is invalid or unexpected given the context, for example an 'array' node when we expected a 'group'. """ + + +class ZarrFutureWarning(FutureWarning): ... + + +class ZarrDeprecationWarning(DeprecationWarning): ... diff --git a/src/zarr/storage/__init__.py b/src/zarr/storage/__init__.py index 6721139375..00df50214f 100644 --- a/src/zarr/storage/__init__.py +++ b/src/zarr/storage/__init__.py @@ -3,6 +3,7 @@ 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 @@ -33,7 +34,7 @@ def __setattr__(self, attr: str, value: Any) -> None: "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'})", - DeprecationWarning, + ZarrDeprecationWarning, stacklevel=1, ) else: diff --git a/tests/test_api.py b/tests/test_api.py index e6cb612a82..4b6394d223 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -5,6 +5,8 @@ import zarr.codecs import zarr.storage +from zarr.storage._local import LocalStore +from zarr.storage._zip import ZipStore if TYPE_CHECKING: import pathlib @@ -38,8 +40,8 @@ save_group, ) from zarr.core.buffer import NDArrayLike -from zarr.errors import MetadataValidationError -from zarr.storage import LocalStore, MemoryStore, ZipStore +from zarr.errors import MetadataValidationError, ZarrDeprecationWarning, ZarrFutureWarning +from zarr.storage import MemoryStore from zarr.storage._utils import normalize_path from zarr.testing.utils import gpu_test @@ -441,7 +443,7 @@ def test_tree() -> None: g3.create_group("baz") g5 = g3.create_group("qux") g5.create_array("baz", shape=(100,), chunks=(10,), dtype="float64") - with pytest.warns(DeprecationWarning): + with pytest.warns(ZarrDeprecationWarning): assert repr(zarr.tree(g1)) == repr(g1.tree()) assert str(zarr.tree(g1)) == str(g1.tree()) @@ -1115,7 +1117,7 @@ def test_tree() -> None: def test_open_positional_args_deprecated() -> None: store = MemoryStore() - with pytest.warns(FutureWarning, match="pass"): + with pytest.warns(ZarrFutureWarning, match="pass"): zarr.api.synchronous.open(store, "w", shape=(1,)) @@ -1123,9 +1125,9 @@ def test_save_array_positional_args_deprecated() -> None: store = MemoryStore() with warnings.catch_warnings(): warnings.filterwarnings( - "ignore", message="zarr_version is deprecated", category=DeprecationWarning + "ignore", message="zarr_version is deprecated", category=ZarrDeprecationWarning ) - with pytest.warns(FutureWarning, match="pass"): + with pytest.warns(ZarrFutureWarning, match="pass"): save_array( store, np.ones( @@ -1137,13 +1139,13 @@ def test_save_array_positional_args_deprecated() -> None: def test_group_positional_args_deprecated() -> None: store = MemoryStore() - with pytest.warns(FutureWarning, match="pass"): + with pytest.warns(ZarrFutureWarning, match="pass"): group(store, True) def test_open_group_positional_args_deprecated() -> None: store = MemoryStore() - with pytest.warns(FutureWarning, match="pass"): + with pytest.warns(ZarrFutureWarning, match="pass"): open_group(store, "w") diff --git a/tests/test_array.py b/tests/test_array.py index bc27a30593..6a631e9d21 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -56,7 +56,12 @@ from zarr.core.indexing import BasicIndexer, ceildiv from zarr.core.metadata.v2 import ArrayV2Metadata from zarr.core.sync import sync -from zarr.errors import ContainsArrayError, ContainsGroupError +from zarr.errors import ( + ContainsArrayError, + ContainsGroupError, + ZarrDeprecationWarning, + ZarrFutureWarning, +) from zarr.storage import LocalStore, MemoryStore, StorePath from .test_dtype.conftest import zdtype_examples @@ -251,11 +256,11 @@ def test_array_v3_fill_value(store: MemoryStore, fill_value: int, dtype_str: str async def test_create_deprecated() -> None: - with pytest.warns(DeprecationWarning): - with pytest.warns(FutureWarning, match=re.escape("Pass shape=(2, 2) as keyword args")): + with pytest.warns(ZarrDeprecationWarning): + with pytest.warns(ZarrFutureWarning, match=re.escape("Pass shape=(2, 2) as keyword args")): await zarr.AsyncArray.create(MemoryStore(), (2, 2), dtype="f8") # type: ignore[call-overload] - with pytest.warns(DeprecationWarning): - with pytest.warns(FutureWarning, match=re.escape("Pass shape=(2, 2) as keyword args")): + with pytest.warns(ZarrDeprecationWarning): + with pytest.warns(ZarrFutureWarning, match=re.escape("Pass shape=(2, 2) as keyword args")): zarr.Array.create(MemoryStore(), (2, 2), dtype="f8") @@ -263,34 +268,34 @@ def test_selection_positional_args_deprecated() -> None: store = MemoryStore() arr = zarr.create_array(store, shape=(2, 2), dtype="f8") - with pytest.warns(FutureWarning, match="Pass out"): + with pytest.warns(ZarrFutureWarning, match="Pass out"): arr.get_basic_selection(..., NDBuffer(array=np.empty((2, 2)))) - with pytest.warns(FutureWarning, match="Pass fields"): + with pytest.warns(ZarrFutureWarning, match="Pass fields"): arr.set_basic_selection(..., 1, None) - with pytest.warns(FutureWarning, match="Pass out"): + with pytest.warns(ZarrFutureWarning, match="Pass out"): arr.get_orthogonal_selection(..., NDBuffer(array=np.empty((2, 2)))) - with pytest.warns(FutureWarning, match="Pass"): + with pytest.warns(ZarrFutureWarning, match="Pass"): arr.set_orthogonal_selection(..., 1, None) - with pytest.warns(FutureWarning, match="Pass"): + with pytest.warns(ZarrFutureWarning, match="Pass"): arr.get_mask_selection(np.zeros((2, 2), dtype=bool), NDBuffer(array=np.empty((0,)))) - with pytest.warns(FutureWarning, match="Pass"): + with pytest.warns(ZarrFutureWarning, match="Pass"): arr.set_mask_selection(np.zeros((2, 2), dtype=bool), 1, None) - with pytest.warns(FutureWarning, match="Pass"): + with pytest.warns(ZarrFutureWarning, match="Pass"): arr.get_coordinate_selection(([0, 1], [0, 1]), NDBuffer(array=np.empty((2,)))) - with pytest.warns(FutureWarning, match="Pass"): + with pytest.warns(ZarrFutureWarning, match="Pass"): arr.set_coordinate_selection(([0, 1], [0, 1]), 1, None) - with pytest.warns(FutureWarning, match="Pass"): + with pytest.warns(ZarrFutureWarning, match="Pass"): arr.get_block_selection((0, slice(None)), NDBuffer(array=np.empty((2, 2)))) - with pytest.warns(FutureWarning, match="Pass"): + with pytest.warns(ZarrFutureWarning, match="Pass"): arr.set_block_selection((0, slice(None)), 1, None) diff --git a/tests/test_dtype/test_npy/test_bytes.py b/tests/test_dtype/test_npy/test_bytes.py index 3f1ba9315e..1fa713a745 100644 --- a/tests/test_dtype/test_npy/test_bytes.py +++ b/tests/test_dtype/test_npy/test_bytes.py @@ -150,7 +150,7 @@ def test_unstable_dtype_warning( Test that we get a warning when serializing a dtype without a zarr v3 spec to json when zarr_format is 3 """ - with pytest.raises(UnstableSpecificationWarning): + with pytest.warns(UnstableSpecificationWarning): zdtype.to_json(zarr_format=3) diff --git a/tests/test_dtype/test_npy/test_string.py b/tests/test_dtype/test_npy/test_string.py index 7c3c6a8cd4..a470cb4d12 100644 --- a/tests/test_dtype/test_npy/test_string.py +++ b/tests/test_dtype/test_npy/test_string.py @@ -131,7 +131,7 @@ def test_unstable_dtype_warning(zdtype: FixedLengthUTF32 | VariableLengthUTF8) - Test that we get a warning when serializing a dtype without a zarr v3 spec to json when zarr_format is 3 """ - with pytest.raises(UnstableSpecificationWarning): + with pytest.warns(UnstableSpecificationWarning): zdtype.to_json(zarr_format=3) diff --git a/tests/test_group.py b/tests/test_group.py index 60a1fcb9bf..64a6b39b10 100644 --- a/tests/test_group.py +++ b/tests/test_group.py @@ -39,7 +39,13 @@ ) from zarr.core.metadata.v3 import ArrayV3Metadata from zarr.core.sync import _collect_aiterator, sync -from zarr.errors import ContainsArrayError, ContainsGroupError, MetadataValidationError +from zarr.errors import ( + ContainsArrayError, + ContainsGroupError, + MetadataValidationError, + ZarrDeprecationWarning, + ZarrFutureWarning, +) from zarr.storage import LocalStore, MemoryStore, StorePath, ZipStore from zarr.storage._common import make_store_path from zarr.storage._utils import _join_paths, normalize_path @@ -648,7 +654,7 @@ def test_group_create_array( array = group.create_array(name=name, shape=shape, dtype=dtype) array[:] = data elif method == "array": - with pytest.warns(DeprecationWarning): + with pytest.warns(ZarrDeprecationWarning): array = group.array(name=name, data=data, shape=shape, dtype=dtype) else: raise AssertionError @@ -659,7 +665,7 @@ def test_group_create_array( a = group.create_array(name=name, shape=shape, dtype=dtype) a[:] = data elif method == "array": - with pytest.raises(ContainsArrayError), pytest.warns(DeprecationWarning): + with pytest.raises(ContainsArrayError), pytest.warns(ZarrDeprecationWarning): a = group.array(name=name, shape=shape, dtype=dtype) a[:] = data @@ -1183,22 +1189,22 @@ def test_create_dataset_with_data(store: Store, zarr_format: ZarrFormat) -> None """ root = Group.from_store(store=store, zarr_format=zarr_format) arr = np.random.random((5, 5)) - with pytest.warns(DeprecationWarning): + with pytest.warns(ZarrDeprecationWarning): data = root.create_dataset("random", data=arr, shape=arr.shape) np.testing.assert_array_equal(np.asarray(data), arr) async def test_create_dataset(store: Store, zarr_format: ZarrFormat) -> None: root = await AsyncGroup.from_store(store=store, zarr_format=zarr_format) - with pytest.warns(DeprecationWarning): + with pytest.warns(ZarrDeprecationWarning): foo = await root.create_dataset("foo", shape=(10,), dtype="uint8") assert foo.shape == (10,) - with pytest.raises(ContainsArrayError), pytest.warns(DeprecationWarning): + with pytest.raises(ContainsArrayError), pytest.warns(ZarrDeprecationWarning): await root.create_dataset("foo", shape=(100,), dtype="int8") _ = await root.create_group("bar") - with pytest.raises(ContainsGroupError), pytest.warns(DeprecationWarning): + with pytest.raises(ContainsGroupError), pytest.warns(ZarrDeprecationWarning): await root.create_dataset("bar", shape=(100,), dtype="int8") @@ -1454,14 +1460,14 @@ def test_group_deprecated_positional_args(method: str) -> None: kwargs = {} root = zarr.group() - with pytest.warns(FutureWarning, match=r"Pass name=.* as keyword args."): + with pytest.warns(ZarrFutureWarning, match=r"Pass name=.* as keyword args."): arr = getattr(root, method)("foo", shape=1, **kwargs) assert arr.shape == (1,) method += "_like" data = np.ones(1) - with pytest.warns(FutureWarning, match=r"Pass name=.*, data=.* as keyword args."): + with pytest.warns(ZarrFutureWarning, match=r"Pass name=.*, data=.* as keyword args."): arr = getattr(root, method)("foo_like", data, **kwargs) assert arr.shape == data.shape diff --git a/tests/test_sync.py b/tests/test_sync.py index 13b475f8da..0061d41727 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -15,6 +15,7 @@ loop, sync, ) +from zarr.errors import ZarrFutureWarning from zarr.storage import MemoryStore @@ -145,7 +146,7 @@ def bar(self) -> list[int]: def test_open_positional_args_deprecate(): store = MemoryStore() - with pytest.warns(FutureWarning, match="pass"): + with pytest.warns(ZarrFutureWarning, match="pass"): zarr.open(store, "w", shape=(1,)) diff --git a/tests/test_v2.py b/tests/test_v2.py index 29f031663f..bf20d066d8 100644 --- a/tests/test_v2.py +++ b/tests/test_v2.py @@ -21,6 +21,7 @@ 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 @@ -229,7 +230,7 @@ def test_v2_non_contiguous(numpy_order: Literal["C", "F"], zarr_order: Literal[" def test_default_compressor_deprecation_warning() -> None: - with pytest.warns(DeprecationWarning, match="default_compressor is deprecated"): + with pytest.warns(ZarrDeprecationWarning, match="default_compressor is deprecated"): zarr.storage.default_compressor = "zarr.codecs.zstd.ZstdCodec()" # type: ignore[attr-defined]