Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
79dd9e2
define zarr-specific FutureWarning and DeprecationWarning
d-v-b May 25, 2025
b2e25cf
Merge branch 'main' of github.com:zarr-developers/zarr-python into re…
d-v-b Jun 30, 2025
7c644eb
make unstablespecificationwarning an instance of zarrfuturewarning
d-v-b Jun 30, 2025
c604075
use pytest.warns instead of pytest.raises
d-v-b Jun 30, 2025
b964ff6
Merge branch 'main' into refactor-warnings
d-v-b Jul 11, 2025
12bea9c
Merge branch 'main' into refactor-warnings
d-v-b Jul 11, 2025
8267c0c
Merge branch 'main' into refactor-warnings
d-v-b Jul 11, 2025
702ef09
Merge branch 'main' of https://github.com/zarr-developers/zarr-python…
d-v-b Jul 31, 2025
64e1405
changelog
d-v-b Jul 31, 2025
d322cad
ensure that all deprecations are ZarrDeprecations
d-v-b Aug 1, 2025
31e63aa
add docstrings and export warnings
d-v-b Aug 1, 2025
917fd3d
fix imports
d-v-b Aug 1, 2025
9055d3b
handle warnings in tests explicitly; make userwarnings ZarrUserWarning
d-v-b Aug 1, 2025
fee48d3
fix doctests by making them more realistic
d-v-b Aug 1, 2025
6a208eb
lint and fix typo
d-v-b Aug 1, 2025
8a2bb9e
Merge branch 'main' into refactor-warnings
d-v-b Aug 1, 2025
a235660
move unstable spec warning to errors
d-v-b Aug 1, 2025
8afdce9
Merge branch 'refactor-warnings' of https://github.com/d-v-b/zarr-pyt…
d-v-b Aug 1, 2025
33a9184
handle warnings in gpu tests
d-v-b Aug 1, 2025
fc72752
handle more warnings
d-v-b Aug 1, 2025
42b4cb5
handle another warning
d-v-b Aug 1, 2025
713bda9
Fix exports
d-v-b Aug 1, 2025
f483eb8
Update src/zarr/errors.py
d-v-b Aug 2, 2025
d029800
Update changes/3098.misc.rst
d-v-b Aug 2, 2025
94ab461
Merge branch 'main' into refactor-warnings
d-v-b Aug 4, 2025
c11328b
Merge branch 'main' into refactor-warnings
d-v-b Aug 4, 2025
fd76671
Merge branch 'main' into refactor-warnings
d-v-b Aug 4, 2025
b7861b7
Merge branch 'main' into refactor-warnings
d-v-b Aug 5, 2025
ba5be4f
Update src/zarr/errors.py
d-v-b Aug 5, 2025
df0eef4
add test to ensure that ambiguous group.open warns
d-v-b Aug 5, 2025
61ff062
update changelog
d-v-b Aug 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
handle warnings in tests explicitly; make userwarnings ZarrUserWarning
  • Loading branch information
d-v-b committed Aug 1, 2025
commit 9055d3b2e15bc2d5e8511199a0c73a78eebcc00b
10 changes: 0 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -403,16 +403,6 @@ addopts = [
]
filterwarnings = [
"error",
# TODO: explicitly filter or catch the warnings below where we expect them to be emitted in the tests
"ignore:Consolidated metadata is currently not part in the Zarr format 3 specification.*:UserWarning",
"ignore:Creating a zarr.buffer.gpu.Buffer with an array that does not support the __cuda_array_interface__.*:UserWarning",
"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.: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",
"ignore:Unclosed client session <aiohttp.client.ClientSession.*:ResourceWarning"
]
markers = [
Expand Down
42 changes: 24 additions & 18 deletions src/zarr/api/asynchronous.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@
create_hierarchy,
)
from zarr.core.metadata import ArrayMetadataDict, ArrayV2Metadata, ArrayV3Metadata
from zarr.errors import GroupNotFoundError, NodeTypeValidationError, ZarrDeprecationWarning
from zarr.errors import (
GroupNotFoundError,
NodeTypeValidationError,
ZarrDeprecationWarning,
ZarrRuntimeWarning,
ZarrUserWarning,
)
from zarr.storage import StorePath
from zarr.storage._common import make_store_path

Expand Down Expand Up @@ -228,7 +234,7 @@ async def consolidate_metadata(
warnings.warn(
"Consolidated metadata is currently not part in the Zarr format 3 specification. It "
"may not be supported by other zarr implementations and may change in the future.",
category=UserWarning,
category=ZarrUserWarning,
stacklevel=1,
)

Expand Down Expand Up @@ -674,13 +680,13 @@ async def group(
store_path = await make_store_path(store, path=path, mode=mode, storage_options=storage_options)

if chunk_store is not None:
warnings.warn("chunk_store is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("chunk_store is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if cache_attrs is not None:
warnings.warn("cache_attrs is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("cache_attrs is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if synchronizer is not None:
warnings.warn("synchronizer is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("synchronizer is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if meta_array is not None:
warnings.warn("meta_array is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("meta_array is not yet implemented", ZarrRuntimeWarning, stacklevel=2)

if attributes is None:
attributes = {}
Expand Down Expand Up @@ -827,13 +833,13 @@ async def open_group(
zarr_format = _handle_zarr_version_or_format(zarr_version=zarr_version, zarr_format=zarr_format)

if cache_attrs is not None:
warnings.warn("cache_attrs is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("cache_attrs is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if synchronizer is not None:
warnings.warn("synchronizer is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("synchronizer is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if meta_array is not None:
warnings.warn("meta_array is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("meta_array is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if chunk_store is not None:
warnings.warn("chunk_store is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("chunk_store is not yet implemented", ZarrRuntimeWarning, stacklevel=2)

store_path = await make_store_path(store, mode=mode, storage_options=storage_options, path=path)
if attributes is None:
Expand Down Expand Up @@ -1011,19 +1017,19 @@ async def create(
)

if synchronizer is not None:
warnings.warn("synchronizer is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("synchronizer is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if chunk_store is not None:
warnings.warn("chunk_store is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("chunk_store is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if cache_metadata is not None:
warnings.warn("cache_metadata is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("cache_metadata is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if cache_attrs is not None:
warnings.warn("cache_attrs is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("cache_attrs is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if object_codec is not None:
warnings.warn("object_codec is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("object_codec is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if read_only is not None:
warnings.warn("read_only is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("read_only is not yet implemented", ZarrRuntimeWarning, stacklevel=2)
if meta_array is not None:
warnings.warn("meta_array is not yet implemented", RuntimeWarning, stacklevel=2)
warnings.warn("meta_array is not yet implemented", ZarrRuntimeWarning, stacklevel=2)

if write_empty_chunks is not None:
_warn_write_empty_chunks_kwarg()
Expand All @@ -1042,7 +1048,7 @@ async def create(
"This is redundant. When both are set, write_empty_chunks will be used instead "
"of the value in config."
)
warnings.warn(UserWarning(msg), stacklevel=1)
warnings.warn(ZarrUserWarning(msg), stacklevel=1)
config_parsed = dataclasses.replace(config_parsed, write_empty_chunks=write_empty_chunks)

return await AsyncArray._create(
Expand Down
8 changes: 4 additions & 4 deletions src/zarr/core/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
)
from zarr.core.metadata.v3 import parse_node_type_array
from zarr.core.sync import sync
from zarr.errors import MetadataValidationError, ZarrDeprecationWarning
from zarr.errors import MetadataValidationError, ZarrDeprecationWarning, ZarrUserWarning
from zarr.registry import (
_parse_array_array_codec,
_parse_array_bytes_codec,
Expand Down Expand Up @@ -232,7 +232,7 @@ async def get_array_metadata(
if zarr_json_bytes is not None and zarray_bytes is not None:
# warn and favor v3
msg = f"Both zarr.json (Zarr format 3) and .zarray (Zarr format 2) metadata objects exist at {store_path}. Zarr v3 will be used."
warnings.warn(msg, stacklevel=1)
warnings.warn(msg, category=ZarrUserWarning, stacklevel=1)
if zarr_json_bytes is None and zarray_bytes is None:
raise FileNotFoundError(store_path)
# set zarr_format based on which keys were found
Expand Down Expand Up @@ -4648,7 +4648,7 @@ def _parse_keep_array_attr(
warnings.warn(
"The 'order' attribute of a Zarr format 2 array does not have a direct analogue in Zarr format 3. "
"The existing order='F' of the source Zarr format 2 array will be ignored.",
UserWarning,
ZarrUserWarning,
stacklevel=2,
)
elif order is None and zarr_format == 2:
Expand Down Expand Up @@ -4937,7 +4937,7 @@ def _parse_deprecated_compressor(
if zarr_format == 3:
warn(
"The `compressor` argument is deprecated. Use `compressors` instead.",
category=UserWarning,
category=ZarrUserWarning,
stacklevel=2,
)
if compressor is None:
Expand Down
2 changes: 2 additions & 0 deletions src/zarr/core/buffer/gpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from zarr.core.buffer import core
from zarr.core.buffer.core import ArrayLike, BufferPrototype, NDArrayLike
from zarr.errors import ZarrUserWarning
from zarr.registry import (
register_buffer,
register_ndbuffer,
Expand Down Expand Up @@ -72,6 +73,7 @@ def __init__(self, array_like: ArrayLike) -> None:
)
warnings.warn(
msg,
category=ZarrUserWarning,
stacklevel=2,
)
self._data = cp.asarray(array_like)
Expand Down
3 changes: 2 additions & 1 deletion src/zarr/core/chunk_grids.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
parse_named_configuration,
parse_shapelike,
)
from zarr.errors import ZarrUserWarning

if TYPE_CHECKING:
from collections.abc import Iterator
Expand Down Expand Up @@ -233,7 +234,7 @@ def _auto_partition(
if shard_shape == "auto":
warnings.warn(
"Automatic shard shape inference is experimental and may change without notice.",
UserWarning,
ZarrUserWarning,
stacklevel=2,
)
_shards_out = ()
Expand Down
2 changes: 2 additions & 0 deletions src/zarr/core/codec_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from zarr.core.common import ChunkCoords, concurrent_map
from zarr.core.config import config
from zarr.core.indexing import SelectorTuple, is_scalar
from zarr.errors import ZarrUserWarning
from zarr.registry import register_pipeline

if TYPE_CHECKING:
Expand Down Expand Up @@ -501,6 +502,7 @@ def codecs_from_list(
warn(
"Combining a `sharding_indexed` codec disables partial reads and "
"writes, which may lead to inefficient performance.",
category=ZarrUserWarning,
stacklevel=3,
)

Expand Down
5 changes: 3 additions & 2 deletions src/zarr/core/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from typing_extensions import ReadOnly

from zarr.core.config import config as zarr_config
from zarr.errors import ZarrRuntimeWarning

if TYPE_CHECKING:
from collections.abc import Awaitable, Callable, Iterator
Expand Down Expand Up @@ -205,7 +206,7 @@ def _warn_write_empty_chunks_kwarg() -> None:
"argument, as in `config={'write_empty_chunks': True}`,"
"or change the global 'array.write_empty_chunks' configuration variable."
)
warnings.warn(msg, RuntimeWarning, stacklevel=2)
warnings.warn(msg, ZarrRuntimeWarning, stacklevel=2)


def _warn_order_kwarg() -> None:
Expand All @@ -216,7 +217,7 @@ def _warn_order_kwarg() -> None:
"argument, as in `config={'order': 'C'}`,"
"or change the global 'array.order' configuration variable."
)
warnings.warn(msg, RuntimeWarning, stacklevel=2)
warnings.warn(msg, ZarrRuntimeWarning, stacklevel=2)


def _default_zarr_format() -> ZarrFormat:
Expand Down
5 changes: 3 additions & 2 deletions src/zarr/core/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
ContainsGroupError,
MetadataValidationError,
ZarrDeprecationWarning,
ZarrUserWarning,
)
from zarr.storage import StoreLike, StorePath
from zarr.storage._common import ensure_no_existing_node, make_store_path
Expand Down Expand Up @@ -553,7 +554,7 @@ async def open(
if zarr_json_bytes is not None and zgroup_bytes is not None:
# warn and favor v3
msg = f"Both zarr.json (Zarr format 3) and .zgroup (Zarr format 2) metadata objects exist at {store_path}. Zarr format 3 will be used."
warnings.warn(msg, stacklevel=1)
warnings.warn(msg, category=ZarrUserWarning, stacklevel=1)
if zarr_json_bytes is None and zgroup_bytes is None:
raise FileNotFoundError(
f"could not find zarr.json or .zgroup objects in {store_path}"
Expand Down Expand Up @@ -3380,7 +3381,7 @@ async def _iter_members(
# in which case `key` cannot be the name of a sub-array or sub-group.
warnings.warn(
f"Object at {e.args[0]} is not recognized as a component of a Zarr hierarchy.",
UserWarning,
ZarrUserWarning,
stacklevel=1,
)
continue
Expand Down
3 changes: 2 additions & 1 deletion src/zarr/core/metadata/v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from zarr.core.chunk_grids import RegularChunkGrid
from zarr.core.dtype import get_data_type_from_json
from zarr.core.dtype.common import OBJECT_CODEC_IDS, DTypeSpec_V2
from zarr.errors import ZarrUserWarning

if TYPE_CHECKING:
from typing import Literal, Self
Expand Down Expand Up @@ -188,7 +189,7 @@ def from_dict(cls, data: dict[str, Any]) -> ArrayV2Metadata:
"This is contrary to the Zarr V2 specification, and will cause an error in the future. "
"Use None (or Null in a JSON document) instead of an empty list of filters."
)
warnings.warn(msg, UserWarning, stacklevel=1)
warnings.warn(msg, ZarrUserWarning, stacklevel=1)
_data["filters"] = None

_data = {k: v for k, v in _data.items() if k in expected}
Expand Down
12 changes: 12 additions & 0 deletions src/zarr/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,15 @@ class ZarrDeprecationWarning(DeprecationWarning):
"""
A warning raised to indicate that a construct will be removed in a future release.
"""


class ZarrUserWarning(UserWarning):
"""
A warning raised to report problems with user code.
"""


class ZarrRuntimeWarning(RuntimeWarning):
"""
A warning for dubious runtime behavior.
"""
2 changes: 2 additions & 0 deletions src/zarr/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from zarr.core.config import BadConfigError, config
from zarr.core.dtype import data_type_registry
from zarr.errors import ZarrUserWarning

if TYPE_CHECKING:
from importlib.metadata import EntryPoint
Expand Down Expand Up @@ -160,6 +161,7 @@ def get_codec_class(key: str, reload_config: bool = False) -> type[Codec]:
warnings.warn(
f"Codec '{key}' not configured in config. Selecting any implementation.",
stacklevel=2,
category=ZarrUserWarning,
)
return list(codec_classes.values())[-1]
selected_codec_cls = codec_classes[config_entry]
Expand Down
4 changes: 3 additions & 1 deletion src/zarr/storage/_fsspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
SuffixByteRequest,
)
from zarr.core.buffer import Buffer
from zarr.errors import ZarrUserWarning
from zarr.storage._common import _dereference_path

if TYPE_CHECKING:
Expand Down Expand Up @@ -101,7 +102,7 @@ class FsspecStore(Store):

Warns
-----
UserWarning
ZarrUserWarning
If the file system (fs) was not created with `asynchronous=True`.

See Also
Expand Down Expand Up @@ -137,6 +138,7 @@ def __init__(
if not self.fs.asynchronous:
warnings.warn(
f"fs ({fs}) was not created with `asynchronous=True`, this may lead to surprising behavior",
category=ZarrUserWarning,
stacklevel=2,
)
if "://" in path and not path.startswith("http"):
Expand Down
6 changes: 5 additions & 1 deletion src/zarr/testing/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import importlib.util
import warnings

from zarr.errors import ZarrUserWarning

if importlib.util.find_spec("pytest") is not None:
from zarr.testing.store import StoreTests
else:
warnings.warn("pytest not installed, skipping test suite", stacklevel=2)
warnings.warn(
"pytest not installed, skipping test suite", category=ZarrUserWarning, stacklevel=2
)

from zarr.testing.utils import assert_bytes_equal

Expand Down
6 changes: 3 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
save_group,
)
from zarr.core.buffer import NDArrayLike
from zarr.errors import MetadataValidationError, ZarrDeprecationWarning
from zarr.errors import MetadataValidationError, ZarrDeprecationWarning, ZarrUserWarning
from zarr.storage import MemoryStore
from zarr.storage._utils import normalize_path
from zarr.testing.utils import gpu_test
Expand Down Expand Up @@ -170,7 +170,7 @@ def test_v2_and_v3_exist_at_same_path(store: Store) -> None:
zarr.create_array(store, shape=(10,), dtype="uint8", zarr_format=3)
zarr.create_array(store, shape=(10,), dtype="uint8", zarr_format=2)
msg = f"Both zarr.json (Zarr format 3) and .zarray (Zarr format 2) metadata objects exist at {store}. Zarr v3 will be used."
with pytest.warns(UserWarning, match=re.escape(msg)):
with pytest.warns(ZarrUserWarning, match=re.escape(msg)):
zarr.open(store=store)


Expand Down Expand Up @@ -1351,7 +1351,7 @@ def test_no_overwrite_open(tmp_path: Path, open_func: Callable, mode: str) -> No
existing_fpath = add_empty_file(tmp_path)

assert existing_fpath.exists()
with contextlib.suppress(FileExistsError, FileNotFoundError, UserWarning):
with contextlib.suppress(FileExistsError, FileNotFoundError, ZarrUserWarning):
open_func(store=store, mode=mode)
if mode == "w":
assert not existing_fpath.exists()
Expand Down
Loading
Loading