diff --git a/pyproject.toml b/pyproject.toml index 493b18822a..02e66c67e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -459,7 +459,6 @@ filterwarnings = [ "ignore:Exception ignored ((on calling weakref callback)|(in[\\s\\S]*Session was never entered)):pytest.PytestUnraisableExceptionWarning", ] markers = [ - "asyncio: mark test as asyncio test", "gpu: mark a test as requiring CuPy and GPU", "s3: mark a test as requiring a (mock) S3 backend via moto", "slow_hypothesis: slow hypothesis tests", diff --git a/tests/conftest.py b/tests/conftest.py index 031c4a4283..c02daf7663 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -54,8 +54,6 @@ from contextlib import AbstractContextManager from typing import Any, Literal - from _pytest.compat import LEGACY_PATH - from zarr.abc.codec import Codec from zarr.core.array import CompressorsLike, FiltersLike, SerializerLike, ShardsLike from zarr.core.chunk_key_encodings import ( @@ -121,14 +119,14 @@ def path_type(request: pytest.FixtureRequest) -> Any: # todo: harmonize this with local_store fixture @pytest.fixture -async def store_path(tmpdir: LEGACY_PATH) -> StorePath: - store = await LocalStore.open(str(tmpdir)) +async def store_path(tmp_path: pathlib.Path) -> StorePath: + store = await LocalStore.open(str(tmp_path)) return StorePath(store) @pytest.fixture -async def local_store(tmpdir: LEGACY_PATH) -> LocalStore: - return await LocalStore.open(str(tmpdir)) +async def local_store(tmp_path: pathlib.Path) -> LocalStore: + return await LocalStore.open(str(tmp_path)) @pytest.fixture @@ -142,26 +140,27 @@ async def memory_store() -> MemoryStore: @pytest.fixture -async def zip_store(tmpdir: LEGACY_PATH) -> ZipStore: - return await ZipStore.open(str(tmpdir / "zarr.zip"), mode="w") +async def zip_store(tmp_path: pathlib.Path) -> ZipStore: + return await ZipStore.open(str(tmp_path / "zarr.zip"), mode="w") @pytest.fixture -async def store(request: pytest.FixtureRequest, tmpdir: LEGACY_PATH) -> Store: +async def store(request: pytest.FixtureRequest, tmp_path: pathlib.Path) -> Store: param = request.param - return await parse_store(param, str(tmpdir)) + return await parse_store(param, str(tmp_path)) @pytest.fixture -async def store2(request: pytest.FixtureRequest, tmpdir: LEGACY_PATH) -> Store: +async def store2(request: pytest.FixtureRequest, tmp_path: pathlib.Path) -> Store: """Fixture to create a second store for testing copy operations between stores""" param = request.param - store2_path = tmpdir.mkdir("store2") + store2_path = tmp_path / "store2" + store2_path.mkdir() return await parse_store(param, str(store2_path)) @pytest.fixture(params=["local", "memory", "zip"]) -def sync_store(request: pytest.FixtureRequest, tmp_path: LEGACY_PATH) -> Store: +def sync_store(request: pytest.FixtureRequest, tmp_path: pathlib.Path) -> Store: result = sync(parse_store(request.param, str(tmp_path))) if not isinstance(result, Store): raise TypeError(f"Wrong store class returned by test fixture! got {result} instead") @@ -176,10 +175,10 @@ class AsyncGroupRequest: @pytest.fixture -async def async_group(request: pytest.FixtureRequest, tmpdir: LEGACY_PATH) -> AsyncGroup: +async def async_group(request: pytest.FixtureRequest, tmp_path: pathlib.Path) -> AsyncGroup: param: AsyncGroupRequest = request.param - store = await parse_store(param.store, str(tmpdir)) + store = await parse_store(param.store, str(tmp_path)) return await AsyncGroup.from_store( store, attributes=param.attributes, diff --git a/tests/test_api.py b/tests/test_api.py index 788519969d..121f02c7b2 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -293,7 +293,6 @@ def test_open_array_rectilinear_chunks(tmp_path: Path) -> None: assert z.read_chunk_sizes == ((3, 3, 4), (5, 5)) -@pytest.mark.asyncio async def test_async_array_open_array_not_found() -> None: """Test that AsyncArray.open raises ArrayNotFoundError when array doesn't exist""" store = MemoryStore() @@ -352,16 +351,16 @@ async def test_open_group(memory_store: MemoryStore) -> None: @pytest.mark.parametrize("zarr_format", [None, 2, 3]) -async def test_open_group_unspecified_version(tmpdir: Path, zarr_format: ZarrFormat) -> None: +async def test_open_group_unspecified_version(tmp_path: Path, zarr_format: ZarrFormat) -> None: """Regression test for https://github.com/zarr-developers/zarr-python/issues/2175""" # create a group with specified zarr format (could be 2, 3, or None) _ = await zarr.api.asynchronous.open_group( - store=str(tmpdir), mode="w", zarr_format=zarr_format, attributes={"foo": "bar"} + store=str(tmp_path), mode="w", zarr_format=zarr_format, attributes={"foo": "bar"} ) # now open that group without specifying the format - g2 = await zarr.api.asynchronous.open_group(store=str(tmpdir), mode="r") + g2 = await zarr.api.asynchronous.open_group(store=str(tmp_path), mode="r") assert g2.attrs == {"foo": "bar"} diff --git a/tests/test_api/test_synchronous.py b/tests/test_api/test_synchronous.py index 9e4aab438d..9b15ec32f6 100644 --- a/tests/test_api/test_synchronous.py +++ b/tests/test_api/test_synchronous.py @@ -44,7 +44,7 @@ def test_docstrings_match(callable_name: str) -> None: @pytest.mark.parametrize( ("parameter_name", "array_creation_routines"), [ - ( + pytest.param( ("store", "path"), ( asynchronous.create_array, @@ -54,8 +54,9 @@ def test_docstrings_match(callable_name: str) -> None: zarr.AsyncGroup.create_array, zarr.Group.create_array, ), + id="store-path-create_array_group", ), - ( + pytest.param( ( "store", "path", @@ -65,8 +66,9 @@ def test_docstrings_match(callable_name: str) -> None: synchronous.create, zarr.Group.create, ), + id="store-path-create", ), - ( + pytest.param( ( ( "filters", @@ -87,9 +89,9 @@ def test_docstrings_match(callable_name: str) -> None: zarr.AsyncGroup.create_array, zarr.Group.create_array, ), + id="encoding-params-create_and_array", ), ], - ids=str, ) def test_docstring_consistent_parameters( parameter_name: str, array_creation_routines: tuple[Callable[[Any], Any], ...] diff --git a/tests/test_buffer.py b/tests/test_buffer.py index b50e5abb67..b4a16ed1de 100644 --- a/tests/test_buffer.py +++ b/tests/test_buffer.py @@ -44,7 +44,6 @@ def test_nd_array_like(xp: types.ModuleType) -> None: assert isinstance(ary, NDArrayLike) -@pytest.mark.asyncio async def test_async_array_prototype() -> None: """Test the use of a custom buffer prototype""" @@ -73,7 +72,6 @@ async def test_async_array_prototype() -> None: @gpu_test -@pytest.mark.asyncio async def test_async_array_gpu_prototype() -> None: """Test the use of the GPU buffer prototype""" @@ -97,7 +95,6 @@ async def test_async_array_gpu_prototype() -> None: assert cp.array_equal(expect, got) -@pytest.mark.asyncio async def test_codecs_use_of_prototype() -> None: expect = np.zeros((10, 10), dtype="uint16", order="F") a = await zarr.api.asynchronous.create_array( @@ -126,7 +123,6 @@ async def test_codecs_use_of_prototype() -> None: @gpu_test -@pytest.mark.asyncio async def test_codecs_use_of_gpu_prototype() -> None: expect = cp.zeros((10, 10), dtype="uint16", order="F") a = await zarr.api.asynchronous.create_array( @@ -155,7 +151,6 @@ async def test_codecs_use_of_gpu_prototype() -> None: @gpu_test -@pytest.mark.asyncio async def test_sharding_use_of_gpu_prototype() -> None: with zarr.config.enable_gpu(): expect = cp.zeros((10, 10), dtype="uint16", order="F") diff --git a/tests/test_docs.py b/tests/test_docs.py index 02dca225b0..9c42a0521a 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -12,7 +12,6 @@ from __future__ import annotations -import os from collections import defaultdict from pathlib import Path from typing import TYPE_CHECKING, Any @@ -82,7 +81,9 @@ def _session_params(root: Path) -> list[Any]: @pytest.fixture -def docs_s3_backend(moto_server: str) -> Generator[None, None, None]: +def docs_s3_backend( + moto_server: str, monkeypatch: pytest.MonkeyPatch +) -> Generator[None, None, None]: """Point docs S3 examples at the shared moto server (tests/conftest.py) via a process-wide AWS_ENDPOINT_URL, so a block can use a bare s3:// URL with no storage_options (see spike in the design notes). The server lifecycle belongs to the @@ -92,8 +93,7 @@ def docs_s3_backend(moto_server: str) -> Generator[None, None, None]: botocore = pytest.importorskip("botocore") requests = pytest.importorskip("requests") - prev_endpoint = os.environ.get("AWS_ENDPOINT_URL") - os.environ["AWS_ENDPOINT_URL"] = moto_server + monkeypatch.setenv("AWS_ENDPOINT_URL", moto_server) session = botocore.session.Session() client = session.create_client("s3", endpoint_url=moto_server, region_name="us-east-1") @@ -103,15 +103,9 @@ def docs_s3_backend(moto_server: str) -> Generator[None, None, None]: try: yield finally: - # Reset moto state and restore AWS_ENDPOINT_URL; the shared server keeps running - # (the moto_server fixture stops it at session end). - try: - requests.post(f"{moto_server}moto-api/reset") - finally: - if prev_endpoint is None: - os.environ.pop("AWS_ENDPOINT_URL", None) - else: - os.environ["AWS_ENDPOINT_URL"] = prev_endpoint + # Reset moto state; AWS_ENDPOINT_URL is restored automatically by monkeypatch. + # The shared server keeps running (the moto_server fixture stops it at session end). + requests.post(f"{moto_server}moto-api/reset") def test_markers_attribute_is_parsed(tmp_path: Path) -> None: diff --git a/tests/test_group.py b/tests/test_group.py index e05df0dfcb..692b88c8af 100644 --- a/tests/test_group.py +++ b/tests/test_group.py @@ -54,17 +54,16 @@ from .conftest import meta_from_array, parse_store if TYPE_CHECKING: + import pathlib from collections.abc import Callable - from _pytest.compat import LEGACY_PATH - from zarr.core.buffer.core import Buffer from zarr.core.common import JSON, ZarrFormat @pytest.fixture(params=["local", "memory", "zip"]) -async def store(request: pytest.FixtureRequest, tmpdir: LEGACY_PATH) -> Store: - result = await parse_store(request.param, str(tmpdir)) +async def store(request: pytest.FixtureRequest, tmp_path: pathlib.Path) -> Store: + result = await parse_store(request.param, str(tmp_path)) if not isinstance(result, Store): raise TypeError(f"Wrong store class returned by test fixture! got {result} instead") return result diff --git a/tests/test_properties.py b/tests/test_properties.py index 3f71fdf493..33888bfd4e 100644 --- a/tests/test_properties.py +++ b/tests/test_properties.py @@ -119,7 +119,6 @@ def test_array_creates_implicit_groups(array): # this decorator removes timeout; not ideal but it should avoid intermittent CI failures -@pytest.mark.asyncio @settings(deadline=None) @pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning") @given(data=st.data()) @@ -146,7 +145,6 @@ async def test_basic_indexing(data: st.DataObject) -> None: # TODO test async setitem? -@pytest.mark.asyncio @settings(deadline=None) @pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning") @given(data=st.data()) @@ -156,7 +154,6 @@ async def test_basic_indexing_complex_rectilinear(data: st.DataObject) -> None: assert_array_equal(nparray[indexer], zarray[indexer]) -@pytest.mark.asyncio @given(data=st.data()) @pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning") async def test_oindex(data: st.DataObject) -> None: @@ -193,7 +190,6 @@ async def test_oindex(data: st.DataObject) -> None: # note: async oindex setitem not yet implemented -@pytest.mark.asyncio @given(data=st.data()) @pytest.mark.filterwarnings("ignore::zarr.core.dtype.common.UnstableSpecificationWarning") async def test_vindex(data: st.DataObject) -> None: diff --git a/tests/test_store/test_core.py b/tests/test_store/test_core.py index f2c81b87f9..0ba0330d08 100644 --- a/tests/test_store/test_core.py +++ b/tests/test_store/test_core.py @@ -4,7 +4,6 @@ from typing import Any, Literal import pytest -from _pytest.compat import LEGACY_PATH import zarr from zarr import Group @@ -163,7 +162,7 @@ async def test_make_store_path_none(path: str) -> None: @pytest.mark.parametrize("store_type", [str, Path]) @pytest.mark.parametrize("mode", ["r", "w"]) async def test_make_store_path_local( - tmpdir: LEGACY_PATH, + tmp_path: Path, store_type: type[str] | type[Path] | type[LocalStore], path: str, mode: AccessModeLiteral, @@ -171,10 +170,10 @@ async def test_make_store_path_local( """ Test the various ways of invoking make_store_path that create a LocalStore """ - store_like = store_type(str(tmpdir)) + store_like = store_type(str(tmp_path)) store_path = await make_store_path(store_like, path=path, mode=mode) assert isinstance(store_path.store, LocalStore) - assert Path(store_path.store.root) == Path(tmpdir) + assert Path(store_path.store.root) == Path(tmp_path) assert store_path.path == normalize_path(path) assert store_path.read_only == (mode == "r") @@ -336,7 +335,7 @@ def test_relativize_path_invalid() -> None: _relativize_path(path="a/b/c", prefix="b") -def test_different_open_mode(tmp_path: LEGACY_PATH) -> None: +def test_different_open_mode(tmp_path: Path) -> None: # Test with a store that implements .with_read_only() store = MemoryStore() zarr.create((100,), store=store, zarr_format=2, path="a") diff --git a/tests/test_store/test_local.py b/tests/test_store/test_local.py index 6756bc83d9..c4536e5c49 100644 --- a/tests/test_store/test_local.py +++ b/tests/test_store/test_local.py @@ -29,8 +29,8 @@ async def set(self, store: LocalStore, key: str, value: Buffer) -> None: (store.root / key).write_bytes(value.to_bytes()) @pytest.fixture - def store_kwargs(self, tmpdir: str) -> dict[str, str]: - return {"root": str(tmpdir)} + def store_kwargs(self, tmp_path: pathlib.Path) -> dict[str, str]: + return {"root": str(tmp_path)} def test_store_repr(self, store: LocalStore) -> None: assert str(store) == f"file://{store.root.as_posix()}"