Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 0 additions & 3 deletions docs/api/zarr/testing/conftest.md

This file was deleted.

1 change: 0 additions & 1 deletion docs/api/zarr/testing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ title: testing
See the following sub-modules:

- [buffer](./buffer.md)
- [conftest](./conftest.md)
- [stateful](./stateful.md)
- [store](./store.md)
- [strategies](./strategies.md)
Expand Down
1 change: 0 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ nav:
- Testing:
- api/zarr/testing/index.md
- api/zarr/testing/buffer.md
- api/zarr/testing/conftest.md
- api/zarr/testing/stateful.md
- api/zarr/testing/store.md
- api/zarr/testing/strategies.md
Expand Down
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ exclude_also = [
[tool.coverage.run]
omit = [
"bench/compress_normal.py",
"src/zarr/testing/conftest.py", # only for downstream projects
]

[tool.hatch]
Expand Down
14 changes: 13 additions & 1 deletion src/zarr/testing/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import importlib.util
import warnings
from typing import TYPE_CHECKING

from zarr.errors import ZarrUserWarning

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

from zarr.testing.utils import assert_bytes_equal
if TYPE_CHECKING:
import pytest


def pytest_configure(config: "pytest.Config") -> None:
# The tests in zarr.testing are intended to be run by downstream projects.
# To allow those downstream projects to run with `--strict-markers`, we need
# to register an entry point with pytest11 and register our "plugin" with it,
# which just registers the markers used in zarr.testing
config.addinivalue_line("markers", "gpu: mark a test as requiring CuPy and GPU")


# TODO: import public buffer tests?

Expand Down
9 changes: 0 additions & 9 deletions src/zarr/testing/conftest.py

This file was deleted.

16 changes: 9 additions & 7 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ def test_create(memory_store: Store) -> None:
assert z.chunks == (40,)

# create array with float shape
with pytest.raises(TypeError):
with pytest.raises(TypeError, match="Expected an iterable of integers"):
z = create(shape=(400.5, 100), store=store, overwrite=True) # type: ignore[arg-type]

# create array with float chunk shape
with pytest.raises(TypeError):
with pytest.raises(TypeError, match="'float' object is not iterable"):
z = create(shape=(400, 100), chunks=(16, 16.5), store=store, overwrite=True) # type: ignore[arg-type]


Expand Down Expand Up @@ -378,7 +378,7 @@ def test_save(store: Store, n_args: int, n_kwargs: int, path: None | str) -> Non
kwargs = {f"arg_{i}": data for i in range(n_kwargs)}

if n_kwargs == 0 and n_args == 0:
with pytest.raises(ValueError):
with pytest.raises(ValueError, match="at least one array must be provided"):
save(store, path=path)
elif n_args == 1 and n_kwargs == 0:
save(store, *args, path=path)
Expand All @@ -397,17 +397,19 @@ def test_save(store: Store, n_args: int, n_kwargs: int, path: None | str) -> Non


def test_save_errors() -> None:
with pytest.raises(ValueError):
with pytest.raises(ValueError, match="at least one array must be provided"):
# no arrays provided
save_group("data/group.zarr")
with pytest.raises(TypeError):
with pytest.raises(TypeError, match="missing 1 required positional argument: 'arr'"):
# no array provided
save_array("data/group.zarr") # type: ignore[call-arg]
with pytest.raises(ValueError):
with pytest.raises(ValueError, match="at least one array must be provided"):
# no arrays provided
save("data/group.zarr")
a = np.arange(10)
with pytest.raises(TypeError):
with pytest.raises(
TypeError, match="Keyword argument 'mode' must be a numpy or other NDArrayLike array"
):
# mode is no valid argument and would get handled as an array
zarr.save("data/example.zarr", a, mode="w")

Expand Down
27 changes: 8 additions & 19 deletions tests/test_experimental/test_cache_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,21 +131,14 @@ async def test_cache_expiration(self) -> None:
test_data = CPUBuffer.from_bytes(b"expiring data")
await cached_store.set("expire_key", test_data)

# Should be fresh initially (if _is_key_fresh method exists)
if hasattr(cached_store, "_is_key_fresh"):
assert cached_store._is_key_fresh("expire_key")

# Wait for expiration
await asyncio.sleep(1.1)

# Should now be stale
assert not cached_store._is_key_fresh("expire_key")
else:
# Skip freshness check if method doesn't exist
await asyncio.sleep(1.1)
# Just verify the data is still accessible
result = await cached_store.get("expire_key", default_buffer_prototype())
assert result is not None
# Should be fresh initially
assert cached_store._is_key_fresh("expire_key")

# Wait for expiration
await asyncio.sleep(1.1)

# Should now be stale
assert not cached_store._is_key_fresh("expire_key")

async def test_cache_set_data_false(self, source_store: Store, cache_store: Store) -> None:
"""Test behavior when cache_set_data=False."""
Expand Down Expand Up @@ -225,10 +218,6 @@ async def test_stale_cache_refresh(self) -> None:

async def test_infinity_max_age(self, cached_store: CacheStore) -> None:
"""Test that 'infinity' max_age means cache never expires."""
# Skip test if _is_key_fresh method doesn't exist
if not hasattr(cached_store, "_is_key_fresh"):
pytest.skip("_is_key_fresh method not implemented")

test_data = CPUBuffer.from_bytes(b"eternal data")
await cached_store.set("eternal_key", test_data)

Expand Down
12 changes: 6 additions & 6 deletions tests/test_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ def test_group_getitem(store: Store, zarr_format: ZarrFormat, consolidated: bool
assert group["subgroup"]["subarray"] == subsubarray
assert group["subgroup/subarray"] == subsubarray

with pytest.raises(KeyError):
with pytest.raises(KeyError, match="nope"):
group["nope"]

with pytest.raises(KeyError, match="subarray/subsubarray"):
Expand Down Expand Up @@ -483,11 +483,11 @@ def test_group_delitem(store: Store, zarr_format: ZarrFormat, consolidated: bool
assert group["subarray"] == subarray

del group["subgroup"]
with pytest.raises(KeyError):
with pytest.raises(KeyError, match="subgroup"):
group["subgroup"]

del group["subarray"]
with pytest.raises(KeyError):
with pytest.raises(KeyError, match="subarray"):
group["subarray"]


Expand Down Expand Up @@ -1060,7 +1060,7 @@ async def test_asyncgroup_getitem(store: Store, zarr_format: ZarrFormat) -> None
assert await agroup.getitem(sub_group_path) == sub_group

# check that asking for a nonexistent key raises KeyError
with pytest.raises(KeyError):
with pytest.raises(KeyError, match="foo"):
await agroup.getitem("foo")


Expand Down Expand Up @@ -1316,7 +1316,7 @@ async def test_require_group(store: LocalStore | MemoryStore, zarr_format: ZarrF
# await root.require_group("foo", overwrite=True)

# test that requiring a group where an array is fails
with pytest.raises(TypeError):
with pytest.raises(TypeError, match="Incompatible object"):
await foo_group.require_group("bar")


Expand Down Expand Up @@ -1650,7 +1650,7 @@ def test_delitem_removes_children(store: Store, zarr_format: ZarrFormat) -> None
arr = g1.create_array("0/0/0", shape=(1,), dtype="uint8")
arr[:] = 1
del g1["0"]
with pytest.raises(KeyError):
with pytest.raises(KeyError, match="0/0"):
g1["0/0"]


Expand Down
18 changes: 11 additions & 7 deletions tests/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ def test_replace_ellipsis() -> None:
[
(42, "uint8"),
pytest.param(
(b"aaa", 1, 4.2), [("foo", "S3"), ("bar", "i4"), ("baz", "f8")], marks=pytest.mark.xfail
(b"aaa", 1, 4.2),
[("foo", "S3"), ("bar", "i4"), ("baz", "f8")],
marks=pytest.mark.filterwarnings("ignore::zarr.errors.UnstableSpecificationWarning"),
),
],
)
Expand All @@ -171,8 +173,8 @@ def test_get_basic_selection_0d(store: StorePath, use_out: bool, value: Any, dty

assert_array_equal(arr_np, arr_z.get_basic_selection(Ellipsis))
assert_array_equal(arr_np, arr_z[...])
assert value == arr_z.get_basic_selection(())
assert value == arr_z[()]
assert arr_np[()] == arr_z.get_basic_selection(())
assert arr_np[()] == arr_z[()]

if use_out:
# test out param
Expand Down Expand Up @@ -598,7 +600,9 @@ def test_fancy_indexing_doesnt_mix_with_implicit_slicing(store: StorePath) -> No
[
(42, "uint8"),
pytest.param(
(b"aaa", 1, 4.2), [("foo", "S3"), ("bar", "i4"), ("baz", "f8")], marks=pytest.mark.xfail
(b"aaa", 1, 4.2),
[("foo", "S3"), ("bar", "i4"), ("baz", "f8")],
marks=pytest.mark.filterwarnings("ignore::zarr.errors.UnstableSpecificationWarning"),
),
],
)
Expand All @@ -612,11 +616,11 @@ def test_set_basic_selection_0d(
assert_array_equal(arr_np_zeros, arr_z)

arr_z.set_basic_selection(Ellipsis, value)
assert_array_equal(value, arr_z)
arr_z[...] = 0
assert_array_equal(arr_np, arr_z)
arr_z[...] = arr_np_zeros[()]
assert_array_equal(arr_np_zeros, arr_z)
arr_z[...] = value
assert_array_equal(value, arr_z)
assert_array_equal(arr_np, arr_z)

# todo: uncomment the structured array tests when we can make them pass,
# or delete them if we formally decide not to support structured dtypes.
Expand Down
6 changes: 3 additions & 3 deletions tests/test_store/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ async def test_contains_invalid_format_raises(local_store: LocalStore, func: _Co
Test contains_group and contains_array raise errors for invalid zarr_formats
"""
store_path = StorePath(local_store)
with pytest.raises(ValueError):
with pytest.raises(ValueError, match="Invalid zarr_format provided. Got 3.0, expected 2 or 3"):
assert await func(store_path, "3.0") # type: ignore[arg-type]


Expand Down Expand Up @@ -214,7 +214,7 @@ async def test_make_store_path_invalid() -> None:
"""
Test that invalid types raise TypeError
"""
with pytest.raises(TypeError):
with pytest.raises(TypeError, match="Unsupported type for store_like: 'int'"):
await make_store_path(1)


Expand Down Expand Up @@ -262,7 +262,7 @@ def test_normalize_path_none() -> None:

@pytest.mark.parametrize("path", [".", ".."])
def test_normalize_path_invalid(path: str) -> None:
with pytest.raises(ValueError):
with pytest.raises(ValueError, match="is invalid because its string representation contains"):
normalize_path(path)


Expand Down
Loading