From 4b173d1b45a43f28d869c1eae126295dc383d9e8 Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Mon, 11 Aug 2025 15:42:05 +0100 Subject: [PATCH 01/10] Added ArrayNotFoundError --- src/zarr/api/asynchronous.py | 5 +++-- src/zarr/errors.py | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/zarr/api/asynchronous.py b/src/zarr/api/asynchronous.py index 78b68caf73..46a7d92158 100644 --- a/src/zarr/api/asynchronous.py +++ b/src/zarr/api/asynchronous.py @@ -40,6 +40,7 @@ ) from zarr.core.metadata import ArrayMetadataDict, ArrayV2Metadata, ArrayV3Metadata from zarr.errors import ( + ArrayNotFoundError, GroupNotFoundError, NodeTypeValidationError, ZarrDeprecationWarning, @@ -1257,7 +1258,7 @@ async def open_array( try: return await AsyncArray.open(store_path, zarr_format=zarr_format) - except FileNotFoundError: + except FileNotFoundError as err: if not store_path.read_only and mode in _CREATE_MODES: overwrite = _infer_overwrite(mode) _zarr_format = zarr_format or _default_zarr_format() @@ -1267,7 +1268,7 @@ async def open_array( overwrite=overwrite, **kwargs, ) - raise + raise ArrayNotFoundError(store_path.store, store_path.path) from err async def open_like( diff --git a/src/zarr/errors.py b/src/zarr/errors.py index 0055ea3c6c..d2cf98c869 100644 --- a/src/zarr/errors.py +++ b/src/zarr/errors.py @@ -1,6 +1,7 @@ from typing import Any __all__ = [ + "ArrayNotFoundError", "BaseZarrError", "ContainsArrayAndGroupError", "ContainsArrayError", @@ -34,6 +35,10 @@ class GroupNotFoundError(BaseZarrError, FileNotFoundError): _msg = "No group found in store {!r} at path {!r}" +class ArrayNotFoundError(BaseZarrError): + _msg = "array not found at path %r' {0!r}" + + class ContainsGroupError(BaseZarrError): """Raised when a group already exists at a certain path.""" From 1b70b66c06856d705df77c6ae291d6c553ac3858 Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Mon, 11 Aug 2025 15:44:24 +0100 Subject: [PATCH 02/10] Add changes file --- changes/3367.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/3367.bugfix.rst diff --git a/changes/3367.bugfix.rst b/changes/3367.bugfix.rst new file mode 100644 index 0000000000..75a3615e8d --- /dev/null +++ b/changes/3367.bugfix.rst @@ -0,0 +1 @@ +Added `~zarr.errors.ArrayNotFoundError`, which is raised when attempting to open a zarr array that does not exist. \ No newline at end of file From 4b7a79fa7aa8716ca381326ead1f3767ff9db339 Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Mon, 11 Aug 2025 15:55:09 +0100 Subject: [PATCH 03/10] Add ArrayNotFoundError to test_api.py --- tests/test_api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index 12acf80589..5648217ba3 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -42,7 +42,7 @@ save_group, ) from zarr.core.buffer import NDArrayLike -from zarr.errors import MetadataValidationError, ZarrDeprecationWarning, ZarrUserWarning +from zarr.errors import ArrayNotFoundError, MetadataValidationError, ZarrDeprecationWarning, ZarrUserWarning from zarr.storage import MemoryStore from zarr.storage._utils import normalize_path from zarr.testing.utils import gpu_test @@ -161,7 +161,7 @@ async def test_open_array(memory_store: MemoryStore, zarr_format: ZarrFormat) -> assert z.read_only # path not found - with pytest.raises(FileNotFoundError): + with pytest.raises(ArrayNotFoundError): zarr.api.synchronous.open(store="doesnotexist", mode="r", zarr_format=zarr_format) @@ -1200,7 +1200,7 @@ async def test_metadata_validation_error() -> None: ) def test_open_array_with_mode_r_plus(store: Store, zarr_format: ZarrFormat) -> None: # 'r+' means read/write (must exist) - with pytest.raises(FileNotFoundError): + with pytest.raises(ArrayNotFoundError): zarr.open_array(store=store, mode="r+", zarr_format=zarr_format) zarr.ones(store=store, shape=(3, 3), zarr_format=zarr_format) z2 = zarr.open_array(store=store, mode="r+") From 5af016e92d00f6e4aec577892b16c112129a9f63 Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Mon, 11 Aug 2025 15:59:16 +0100 Subject: [PATCH 04/10] Fix linting issue --- tests/test_api.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_api.py b/tests/test_api.py index 5648217ba3..18359fbf95 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -42,7 +42,12 @@ save_group, ) from zarr.core.buffer import NDArrayLike -from zarr.errors import ArrayNotFoundError, MetadataValidationError, ZarrDeprecationWarning, ZarrUserWarning +from zarr.errors import ( + ArrayNotFoundError, + MetadataValidationError, + ZarrDeprecationWarning, + ZarrUserWarning, +) from zarr.storage import MemoryStore from zarr.storage._utils import normalize_path from zarr.testing.utils import gpu_test From ff19fc8be80bcbfdd08971b1af11840c4b332bf0 Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Tue, 19 Aug 2025 11:01:27 +0100 Subject: [PATCH 05/10] Address PR comments and add tests to cover new cases --- src/zarr/core/array.py | 25 +++++++++++++++++++++---- src/zarr/errors.py | 24 ++++++++++++++++++++++-- tests/test_api.py | 20 ++++++++++++++++++-- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/zarr/core/array.py b/src/zarr/core/array.py index 819379e12f..5ec0ee99bf 100644 --- a/src/zarr/core/array.py +++ b/src/zarr/core/array.py @@ -117,7 +117,12 @@ ) from zarr.core.metadata.v3 import parse_node_type_array from zarr.core.sync import sync -from zarr.errors import MetadataValidationError, ZarrDeprecationWarning, ZarrUserWarning +from zarr.errors import ( + ArrayNotFoundError, + MetadataValidationError, + ZarrDeprecationWarning, + ZarrUserWarning, +) from zarr.registry import ( _parse_array_array_codec, _parse_array_bytes_codec, @@ -216,11 +221,19 @@ async def get_array_metadata( (store_path / ZATTRS_JSON).get(prototype=cpu_buffer_prototype), ) if zarray_bytes is None: - raise FileNotFoundError(store_path) + msg = ( + "A Zarr V2 array metadata document was not found in store " + f"{store_path.store!r} at path {store_path.path!r}." + ) + raise ArrayNotFoundError(msg) elif zarr_format == 3: zarr_json_bytes = await (store_path / ZARR_JSON).get(prototype=cpu_buffer_prototype) if zarr_json_bytes is None: - raise FileNotFoundError(store_path) + msg = ( + "A Zarr V3 array metadata document was not found in store " + f"{store_path.store!r} at path {store_path.path!r}." + ) + raise ArrayNotFoundError(msg) elif zarr_format is None: zarr_json_bytes, zarray_bytes, zattrs_bytes = await gather( (store_path / ZARR_JSON).get(prototype=cpu_buffer_prototype), @@ -232,7 +245,11 @@ async def get_array_metadata( 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, category=ZarrUserWarning, stacklevel=1) if zarr_json_bytes is None and zarray_bytes is None: - raise FileNotFoundError(store_path) + msg = ( + f"Neither Zarr V3 nor Zarr V2 array metadata documents " + f"were found in store {store_path.store!r} at path {store_path.path!r}." + ) + raise ArrayNotFoundError(msg) # set zarr_format based on which keys were found if zarr_json_bytes is not None: zarr_format = 3 diff --git a/src/zarr/errors.py b/src/zarr/errors.py index d2cf98c869..227416ed2c 100644 --- a/src/zarr/errors.py +++ b/src/zarr/errors.py @@ -1,5 +1,7 @@ from typing import Any +from typing_extensions import deprecated + __all__ = [ "ArrayNotFoundError", "BaseZarrError", @@ -35,8 +37,26 @@ class GroupNotFoundError(BaseZarrError, FileNotFoundError): _msg = "No group found in store {!r} at path {!r}" -class ArrayNotFoundError(BaseZarrError): - _msg = "array not found at path %r' {0!r}" +class ArrayNotFoundError(BaseZarrError, FileNotFoundError): + """ + Raised when an array isn't found at a certain path. + """ + + def __init__(self, *args: Any) -> None: + if len(args) == 1: + # Pre-formatted message + super(BaseZarrError, self).__init__(args[0]) + else: + # Store and path arguments - format them + _msg = "No array found in store {!r} at path {!r}" + super(BaseZarrError, self).__init__(_msg.format(*args)) + +@deprecated("Use NodeNotFoundError instead.", category=None) +class PathNotFoundError(BaseZarrError): + # Backwards compatibility with v2. Superseded by NodeNotFoundError. + ... +class NodeNotFoundError(PathNotFoundError): + """Raised when an array or group does not exist at a certain path.""" class ContainsGroupError(BaseZarrError): diff --git a/tests/test_api.py b/tests/test_api.py index 8e1402404f..7b8c577ee6 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -6,7 +6,7 @@ import zarr.codecs import zarr.storage -from zarr.core.array import init_array +from zarr.core.array import AsyncArray, init_array from zarr.storage import LocalStore, ZipStore from zarr.storage._common import StorePath @@ -44,7 +44,9 @@ from zarr.core.buffer import NDArrayLike from zarr.errors import ( ArrayNotFoundError, + GroupNotFoundError, MetadataValidationError, + NodeNotFoundError, ZarrDeprecationWarning, ZarrUserWarning, ) @@ -190,9 +192,23 @@ async def test_open_array(memory_store: MemoryStore, zarr_format: ZarrFormat) -> assert z.read_only # path not found - with pytest.raises(ArrayNotFoundError): + with pytest.raises((NodeNotFoundError, GroupNotFoundError)): zarr.api.synchronous.open(store="doesnotexist", mode="r", zarr_format=zarr_format) +@pytest.mark.asyncio +async def test_async_array_open_array_not_found(): + """Test that AsyncArray.open raises ArrayNotFoundError when array doesn't exist""" + store = MemoryStore() + # Try to open an array that does not exist + with pytest.raises(ArrayNotFoundError): + await AsyncArray.open(store, zarr_format=2) + +def test_array_open_array_not_found_sync(): + """Test that Array.open raises ArrayNotFoundError when array doesn't exist""" + store = MemoryStore() + # Try to open an array that does not exist + with pytest.raises(ArrayNotFoundError): + Array.open(store) @pytest.mark.parametrize("store", ["memory", "local", "zip"], indirect=True) def test_v2_and_v3_exist_at_same_path(store: Store) -> None: From e774c2f35df984b1d07649744761577015e0859e Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Tue, 19 Aug 2025 11:07:39 +0100 Subject: [PATCH 06/10] Fix linting errors --- src/zarr/core/array.py | 2 +- src/zarr/errors.py | 3 +++ tests/test_api.py | 27 +++++++++++++++------------ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/zarr/core/array.py b/src/zarr/core/array.py index 5ec0ee99bf..fd5ebc45d3 100644 --- a/src/zarr/core/array.py +++ b/src/zarr/core/array.py @@ -223,7 +223,7 @@ async def get_array_metadata( if zarray_bytes is None: msg = ( "A Zarr V2 array metadata document was not found in store " - f"{store_path.store!r} at path {store_path.path!r}." + f"{store_path.store!r} at path {store_path.path!r}." ) raise ArrayNotFoundError(msg) elif zarr_format == 3: diff --git a/src/zarr/errors.py b/src/zarr/errors.py index 227416ed2c..98425dab69 100644 --- a/src/zarr/errors.py +++ b/src/zarr/errors.py @@ -51,10 +51,13 @@ def __init__(self, *args: Any) -> None: _msg = "No array found in store {!r} at path {!r}" super(BaseZarrError, self).__init__(_msg.format(*args)) + @deprecated("Use NodeNotFoundError instead.", category=None) class PathNotFoundError(BaseZarrError): # Backwards compatibility with v2. Superseded by NodeNotFoundError. ... + + class NodeNotFoundError(PathNotFoundError): """Raised when an array or group does not exist at a certain path.""" diff --git a/tests/test_api.py b/tests/test_api.py index 7b8c577ee6..c346fe477c 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -77,11 +77,11 @@ def test_create(memory_store: Store) -> None: # create array with float shape with pytest.raises(TypeError): - z = create(shape=(400.5, 100), store=store, overwrite=True) # type: ignore [arg-type] + z = create(shape=(400.5, 100), store=store, overwrite=True) # create array with float chunk shape with pytest.raises(TypeError): - z = create(shape=(400, 100), chunks=(16, 16.5), store=store, overwrite=True) # type: ignore [arg-type] + z = create(shape=(400, 100), chunks=(16, 16.5), store=store, overwrite=True) # TODO: parametrize over everything this function takes @@ -195,21 +195,24 @@ async def test_open_array(memory_store: MemoryStore, zarr_format: ZarrFormat) -> with pytest.raises((NodeNotFoundError, GroupNotFoundError)): zarr.api.synchronous.open(store="doesnotexist", mode="r", zarr_format=zarr_format) + @pytest.mark.asyncio -async def test_async_array_open_array_not_found(): +async def test_async_array_open_array_not_found() -> None: """Test that AsyncArray.open raises ArrayNotFoundError when array doesn't exist""" store = MemoryStore() # Try to open an array that does not exist with pytest.raises(ArrayNotFoundError): await AsyncArray.open(store, zarr_format=2) -def test_array_open_array_not_found_sync(): + +def test_array_open_array_not_found_sync() -> None: """Test that Array.open raises ArrayNotFoundError when array doesn't exist""" store = MemoryStore() # Try to open an array that does not exist with pytest.raises(ArrayNotFoundError): Array.open(store) + @pytest.mark.parametrize("store", ["memory", "local", "zip"], indirect=True) def test_v2_and_v3_exist_at_same_path(store: Store) -> None: zarr.create_array(store, shape=(10,), dtype="uint8", zarr_format=3) @@ -287,7 +290,7 @@ def test_save(store: Store, n_args: int, n_kwargs: int, path: None | str) -> Non assert isinstance(array, Array) assert_array_equal(array[:], data) else: - save(store, *args, path=path, **kwargs) # type: ignore [arg-type] + save(store, *args, path=path, **kwargs) group = zarr.api.synchronous.open(store, path=path) assert isinstance(group, Group) for array in group.array_values(): @@ -303,7 +306,7 @@ def test_save_errors() -> None: save_group("data/group.zarr") with pytest.raises(TypeError): # no array provided - save_array("data/group.zarr") # type: ignore[call-arg] + save_array("data/group.zarr") with pytest.raises(ValueError): # no arrays provided save("data/group.zarr") @@ -1218,9 +1221,9 @@ def test_open_modes_creates_group(tmp_path: Path, mode: str) -> None: if mode in ["r", "r+"]: # Expect FileNotFoundError to be raised if 'r' or 'r+' mode with pytest.raises(FileNotFoundError): - zarr.open(store=zarr_dir, mode=mode) # type: ignore[arg-type] + zarr.open(store=zarr_dir, mode=mode) else: - group = zarr.open(store=zarr_dir, mode=mode) # type: ignore[arg-type] + group = zarr.open(store=zarr_dir, mode=mode) assert isinstance(group, Group) @@ -1229,13 +1232,13 @@ async def test_metadata_validation_error() -> None: MetadataValidationError, match="Invalid value for 'zarr_format'. Expected '2, 3, or None'. Got '3.0'.", ): - await zarr.api.asynchronous.open_group(zarr_format="3.0") # type: ignore [arg-type] + await zarr.api.asynchronous.open_group(zarr_format="3.0") with pytest.raises( MetadataValidationError, match="Invalid value for 'zarr_format'. Expected '2, 3, or None'. Got '3.0'.", ): - await zarr.api.asynchronous.open_array(shape=(1,), zarr_format="3.0") # type: ignore [arg-type] + await zarr.api.asynchronous.open_array(shape=(1,), zarr_format="3.0") @pytest.mark.parametrize( @@ -1301,7 +1304,7 @@ def test_api_exports() -> None: assert zarr.api.asynchronous.__all__ == zarr.api.synchronous.__all__ -@gpu_test +@gpu_test # type: ignore[misc] @pytest.mark.parametrize( "store", ["local", "memory", "zip"], @@ -1456,4 +1459,4 @@ def test_auto_chunks(f: Callable[..., Array]) -> None: def test_unimplemented_kwarg_warnings(kwarg_name: str) -> None: kwargs = {kwarg_name: 1} with pytest.warns(RuntimeWarning, match=".* is not yet implemented"): - zarr.create(shape=(1,), **kwargs) # type: ignore[arg-type] + zarr.create(shape=(1,), **kwargs) From e86405a49af9f22cabca61c1a4bbe9c461977ef7 Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Tue, 19 Aug 2025 11:26:36 +0100 Subject: [PATCH 07/10] Add type: ignore comments back in --- tests/test_api.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/test_api.py b/tests/test_api.py index c346fe477c..787c42f903 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -77,11 +77,11 @@ def test_create(memory_store: Store) -> None: # create array with float shape with pytest.raises(TypeError): - z = create(shape=(400.5, 100), store=store, overwrite=True) + z = create(shape=(400.5, 100), store=store, overwrite=True) # type: ignore[arg-type] # create array with float chunk shape with pytest.raises(TypeError): - z = create(shape=(400, 100), chunks=(16, 16.5), store=store, overwrite=True) + z = create(shape=(400, 100), chunks=(16, 16.5), store=store, overwrite=True) # type: ignore[arg-type] # TODO: parametrize over everything this function takes @@ -290,7 +290,7 @@ def test_save(store: Store, n_args: int, n_kwargs: int, path: None | str) -> Non assert isinstance(array, Array) assert_array_equal(array[:], data) else: - save(store, *args, path=path, **kwargs) + save(store, *args, path=path, **kwargs) # type: ignore[arg-type] group = zarr.api.synchronous.open(store, path=path) assert isinstance(group, Group) for array in group.array_values(): @@ -306,7 +306,7 @@ def test_save_errors() -> None: save_group("data/group.zarr") with pytest.raises(TypeError): # no array provided - save_array("data/group.zarr") + save_array("data/group.zarr") # type: ignore[call-arg] with pytest.raises(ValueError): # no arrays provided save("data/group.zarr") @@ -1221,9 +1221,9 @@ def test_open_modes_creates_group(tmp_path: Path, mode: str) -> None: if mode in ["r", "r+"]: # Expect FileNotFoundError to be raised if 'r' or 'r+' mode with pytest.raises(FileNotFoundError): - zarr.open(store=zarr_dir, mode=mode) + zarr.open(store=zarr_dir, mode=mode) # type: ignore[arg-type] else: - group = zarr.open(store=zarr_dir, mode=mode) + group = zarr.open(store=zarr_dir, mode=mode) # type: ignore[arg-type] assert isinstance(group, Group) @@ -1232,13 +1232,13 @@ async def test_metadata_validation_error() -> None: MetadataValidationError, match="Invalid value for 'zarr_format'. Expected '2, 3, or None'. Got '3.0'.", ): - await zarr.api.asynchronous.open_group(zarr_format="3.0") + await zarr.api.asynchronous.open_group(zarr_format="3.0") # type: ignore[arg-type] with pytest.raises( MetadataValidationError, match="Invalid value for 'zarr_format'. Expected '2, 3, or None'. Got '3.0'.", ): - await zarr.api.asynchronous.open_array(shape=(1,), zarr_format="3.0") + await zarr.api.asynchronous.open_array(shape=(1,), zarr_format="3.0") # type: ignore[arg-type] @pytest.mark.parametrize( @@ -1304,7 +1304,7 @@ def test_api_exports() -> None: assert zarr.api.asynchronous.__all__ == zarr.api.synchronous.__all__ -@gpu_test # type: ignore[misc] +@gpu_test @pytest.mark.parametrize( "store", ["local", "memory", "zip"], @@ -1459,4 +1459,4 @@ def test_auto_chunks(f: Callable[..., Array]) -> None: def test_unimplemented_kwarg_warnings(kwarg_name: str) -> None: kwargs = {kwarg_name: 1} with pytest.warns(RuntimeWarning, match=".* is not yet implemented"): - zarr.create(shape=(1,), **kwargs) + zarr.create(shape=(1,), **kwargs) # type: ignore[arg-type] From c5f9a621ac8d93502000d2fcda4104e4eb2d6c02 Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Tue, 19 Aug 2025 13:52:49 +0100 Subject: [PATCH 08/10] Change inheritance of errors so Group and Array inherit from Node --- src/zarr/errors.py | 36 +++++++++++++++++++++++------------- tests/test_api.py | 2 +- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/zarr/errors.py b/src/zarr/errors.py index 98425dab69..867e801e18 100644 --- a/src/zarr/errors.py +++ b/src/zarr/errors.py @@ -1,7 +1,5 @@ from typing import Any -from typing_extensions import deprecated - __all__ = [ "ArrayNotFoundError", "BaseZarrError", @@ -29,15 +27,22 @@ def __init__(self, *args: Any) -> None: super().__init__(self._msg.format(*args)) -class GroupNotFoundError(BaseZarrError, FileNotFoundError): +class NodeNotFoundError(BaseZarrError, FileNotFoundError): """ - Raised when a group isn't found at a certain path. + Raised when a node (array or group) is not found at a certain path. """ - _msg = "No group found in store {!r} at path {!r}" + def __init__(self, *args: Any) -> None: + if len(args) == 1: + # Pre-formatted message + super(BaseZarrError, self).__init__(args[0]) + else: + # Store and path arguments - format them + _msg = "No node found in store {!r} at path {!r}" + super(BaseZarrError, self).__init__(_msg.format(*args)) -class ArrayNotFoundError(BaseZarrError, FileNotFoundError): +class ArrayNotFoundError(NodeNotFoundError): """ Raised when an array isn't found at a certain path. """ @@ -52,14 +57,19 @@ def __init__(self, *args: Any) -> None: super(BaseZarrError, self).__init__(_msg.format(*args)) -@deprecated("Use NodeNotFoundError instead.", category=None) -class PathNotFoundError(BaseZarrError): - # Backwards compatibility with v2. Superseded by NodeNotFoundError. - ... - +class GroupNotFoundError(NodeNotFoundError): + """ + Raised when a group isn't found at a certain path. + """ -class NodeNotFoundError(PathNotFoundError): - """Raised when an array or group does not exist at a certain path.""" + def __init__(self, *args: Any) -> None: + if len(args) == 1: + # Pre-formatted message + super(BaseZarrError, self).__init__(args[0]) + else: + # Store and path arguments - format them + _msg = "No group found in store {!r} at path {!r}" + super(BaseZarrError, self).__init__(_msg.format(*args)) class ContainsGroupError(BaseZarrError): diff --git a/tests/test_api.py b/tests/test_api.py index 787c42f903..10abc3c02b 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -192,7 +192,7 @@ async def test_open_array(memory_store: MemoryStore, zarr_format: ZarrFormat) -> assert z.read_only # path not found - with pytest.raises((NodeNotFoundError, GroupNotFoundError)): + with pytest.raises(NodeNotFoundError): zarr.api.synchronous.open(store="doesnotexist", mode="r", zarr_format=zarr_format) From 625a3c0e3dfb61e903c142991753f20ab93fd666 Mon Sep 17 00:00:00 2001 From: ruaridhg Date: Tue, 19 Aug 2025 13:56:03 +0100 Subject: [PATCH 09/10] Fix missing import --- tests/test_api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_api.py b/tests/test_api.py index 10abc3c02b..3668ef306a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -44,7 +44,6 @@ from zarr.core.buffer import NDArrayLike from zarr.errors import ( ArrayNotFoundError, - GroupNotFoundError, MetadataValidationError, NodeNotFoundError, ZarrDeprecationWarning, From 2355b13a66e56814779a22105020a211fe84ff93 Mon Sep 17 00:00:00 2001 From: Davis Bennett Date: Thu, 21 Aug 2025 09:37:02 +0200 Subject: [PATCH 10/10] Update changes/3367.bugfix.rst --- changes/3367.bugfix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes/3367.bugfix.rst b/changes/3367.bugfix.rst index 75a3615e8d..9edef00ca6 100644 --- a/changes/3367.bugfix.rst +++ b/changes/3367.bugfix.rst @@ -1 +1 @@ -Added `~zarr.errors.ArrayNotFoundError`, which is raised when attempting to open a zarr array that does not exist. \ No newline at end of file +Added `zarr.errors.ArrayNotFoundError`, which is raised when attempting to open a zarr array that does not exist, and `zarr.errors.NodeNotFoundError`, which is raised when failing to open an array or a group in a context where either an array or a group was expected. \ No newline at end of file