From 8da13336dfa60c2b4412097bc5e58488aebbb66c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 19:28:07 +0200 Subject: [PATCH 1/3] chore(deps): bump the actions group across 1 directory with 8 updates (#176) Bumps the actions group with 8 updates in the / directory: | Package | From | To | | --- | --- | --- | | [prefix-dev/setup-pixi](https://github.com/prefix-dev/setup-pixi) | `0.9.5` | `0.9.6` | | [codecov/codecov-action](https://github.com/codecov/codecov-action) | `6.0.0` | `6.0.1` | | [github/issue-metrics](https://github.com/github/issue-metrics) | `4.2.2` | `4.2.7` | | [j178/prek-action](https://github.com/j178/prek-action) | `2.0.3` | `2.0.4` | | [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.0` | `7.0.1` | | [actions/download-artifact](https://github.com/actions/download-artifact) | `7.0.0` | `8.0.1` | | [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) | `1.13.0` | `1.14.0` | | [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) | `0.5.3` | `0.5.6` | Updates `prefix-dev/setup-pixi` from 0.9.5 to 0.9.6 - [Release notes](https://github.com/prefix-dev/setup-pixi/releases) - [Commits](https://github.com/prefix-dev/setup-pixi/compare/1b2de7f3351f171c8b4dfeb558c639cb58ed4ec0...5185adfbffb4bd703da3010310260805d89ebb11) Updates `codecov/codecov-action` from 6.0.0 to 6.0.1 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/57e3a136b779b570ffcdbf80b3bdc90e7fab3de2...e79a6962e0d4c0c17b229090214935d2e33f8354) Updates `github/issue-metrics` from 4.2.2 to 4.2.7 - [Release notes](https://github.com/github/issue-metrics/releases) - [Commits](https://github.com/github/issue-metrics/compare/c9e9838147fd355dace335ba787f01b6641a400a...1e38d5e62363e14db8019ed7d106b9855bdba6cc) Updates `j178/prek-action` from 2.0.3 to 2.0.4 - [Release notes](https://github.com/j178/prek-action/releases) - [Commits](https://github.com/j178/prek-action/compare/6ad80277337ad479fe43bd70701c3f7f8aa74db3...bdca6f102f98e2b4c7029491a53dfd366469e33d) Updates `actions/upload-artifact` from 7.0.0 to 7.0.1 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v7...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a) Updates `actions/download-artifact` from 7.0.0 to 8.0.1 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v7...3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c) Updates `pypa/gh-action-pypi-publish` from 1.13.0 to 1.14.0 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.13.0...cef221092ed1bacb1cc03d23a2d87d1d172e277b) Updates `zizmorcore/zizmor-action` from 0.5.3 to 0.5.6 - [Release notes](https://github.com/zizmorcore/zizmor-action/releases) - [Commits](https://github.com/zizmorcore/zizmor-action/compare/b1d7e1fb5de872772f31590499237e7cce841e8e...5f14fd08f7cf1cb1609c1e344975f152c7ee938d) --- updated-dependencies: - dependency-name: prefix-dev/setup-pixi dependency-version: 0.9.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: codecov/codecov-action dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: github/issue-metrics dependency-version: 4.2.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: j178/prek-action dependency-version: 2.0.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: actions/upload-artifact dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: actions/download-artifact dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: pypa/gh-action-pypi-publish dependency-version: 1.14.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: zizmorcore/zizmor-action dependency-version: 0.5.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/downstream.yml | 2 +- .github/workflows/gpu_test.yml | 2 +- .github/workflows/hypothesis.yaml | 2 +- .github/workflows/issue-metrics.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 4 ++-- .github/workflows/zarr-metadata-release.yml | 12 ++++++------ .github/workflows/zizmor.yml | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/downstream.yml b/.github/workflows/downstream.yml index 74026233c4..3eb6898895 100644 --- a/.github/workflows/downstream.yml +++ b/.github/workflows/downstream.yml @@ -34,7 +34,7 @@ jobs: persist-credentials: false - name: Set up pixi - uses: prefix-dev/setup-pixi@1b2de7f3351f171c8b4dfeb558c639cb58ed4ec0 # v0.9.5 + uses: prefix-dev/setup-pixi@5185adfbffb4bd703da3010310260805d89ebb11 # v0.9.6 with: manifest-path: xarray/pixi.toml diff --git a/.github/workflows/gpu_test.yml b/.github/workflows/gpu_test.yml index 403441b306..333769cb9e 100644 --- a/.github/workflows/gpu_test.yml +++ b/.github/workflows/gpu_test.yml @@ -76,7 +76,7 @@ jobs: hatch env run --env "$HATCH_ENV" run-coverage - name: Upload coverage - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} flags: gpu diff --git a/.github/workflows/hypothesis.yaml b/.github/workflows/hypothesis.yaml index 4f9467be7d..a456b2aa0a 100644 --- a/.github/workflows/hypothesis.yaml +++ b/.github/workflows/hypothesis.yaml @@ -93,7 +93,7 @@ jobs: key: cache-hypothesis-${{ runner.os }}-${{ github.run_id }} - name: Upload coverage - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} flags: tests diff --git a/.github/workflows/issue-metrics.yml b/.github/workflows/issue-metrics.yml index 14fba5b9ec..510849ef3e 100644 --- a/.github/workflows/issue-metrics.yml +++ b/.github/workflows/issue-metrics.yml @@ -33,7 +33,7 @@ jobs: echo "last_month=$first_day..$last_day" >> "$GITHUB_ENV" - name: Run issue-metrics tool - uses: github/issue-metrics@c9e9838147fd355dace335ba787f01b6641a400a # v4.2.2 + uses: github/issue-metrics@1e38d5e62363e14db8019ed7d106b9855bdba6cc # v4.2.7 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} SEARCH_QUERY: 'repo:zarr-developers/zarr-python is:issue created:${{ env.last_month }} -reason:"not planned"' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 768e660ec2..fec211b4dd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -30,4 +30,4 @@ jobs: uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 with: enable-cache: true - - uses: j178/prek-action@6ad80277337ad479fe43bd70701c3f7f8aa74db3 # v2.0.3 + - uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 03143d3e5b..62e571856b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -78,7 +78,7 @@ jobs: hatch env run --env "$HATCH_ENV" run-coverage - name: Upload coverage if: ${{ matrix.dependency-set == 'optional' && matrix.os == 'ubuntu-latest' }} - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} flags: tests @@ -125,7 +125,7 @@ jobs: run: | hatch env run --env "$HATCH_ENV" run-coverage - name: Upload coverage - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} flags: tests diff --git a/.github/workflows/zarr-metadata-release.yml b/.github/workflows/zarr-metadata-release.yml index 809d502f16..9639fcfdd3 100644 --- a/.github/workflows/zarr-metadata-release.yml +++ b/.github/workflows/zarr-metadata-release.yml @@ -35,7 +35,7 @@ jobs: - name: Build run: hatch build - - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: zarr-metadata-dist path: packages/zarr-metadata/dist @@ -45,7 +45,7 @@ jobs: needs: [build] runs-on: ubuntu-latest steps: - - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: zarr-metadata-dist path: dist @@ -76,7 +76,7 @@ jobs: id-token: write # required for OIDC trusted publishing attestations: write # required for artifact attestations steps: - - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: zarr-metadata-dist path: dist @@ -87,7 +87,7 @@ jobs: subject-path: dist/* - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 upload_testpypi: name: Upload to TestPyPI @@ -101,7 +101,7 @@ jobs: id-token: write attestations: write steps: - - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: zarr-metadata-dist path: dist @@ -112,6 +112,6 @@ jobs: subject-path: dist/* - name: Publish package to TestPyPI - uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 with: repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index da19f22421..7ac4fe5d0e 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -32,4 +32,4 @@ jobs: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 From e63d29da2dd9b85b781ca0629fe8bb9da4552fe2 Mon Sep 17 00:00:00 2001 From: Davis Vann Bennett Date: Tue, 16 Jun 2026 12:49:05 +0200 Subject: [PATCH 2/3] test: modernize pytest usage (tmp_path, auto asyncio, stable ids, monkeypatch) - Migrate legacy `tmpdir`/`_pytest.compat.LEGACY_PATH` fixtures to the stdlib `tmp_path: pathlib.Path` fixture across conftest and tests; remove the private `_pytest.compat` import and fix an inverted annotation. - Remove redundant `@pytest.mark.asyncio` decorators (asyncio_mode="auto" collects async tests automatically) and drop the now-unused `asyncio` and `s3` entries from the pyproject markers list. - Give `test_docstring_consistent_parameters` stable, human-readable parametrize ids via `pytest.param(..., id=...)`. - Use `monkeypatch.setenv` (auto-restored) instead of manual env save/restore in `tests/test_docs.py`. Co-Authored-By: Claude Opus 4.8 (1M context) --- pyproject.toml | 2 -- tests/conftest.py | 29 ++++++++++++++--------------- tests/test_api.py | 7 +++---- tests/test_api/test_synchronous.py | 10 ++++++---- tests/test_buffer.py | 5 ----- tests/test_docs.py | 20 +++++++------------- tests/test_group.py | 7 +++---- tests/test_properties.py | 4 ---- tests/test_store/test_core.py | 9 ++++----- tests/test_store/test_local.py | 4 ++-- 10 files changed, 39 insertions(+), 58 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9f6005f981..71712db728 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -447,9 +447,7 @@ 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 207fba0a44..e9b3f6401d 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 994510aca0..2fc336a461 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()}" From e1526a02881a02267ce4d1152a1f831d6d439121 Mon Sep 17 00:00:00 2001 From: Davis Vann Bennett Date: Mon, 22 Jun 2026 18:40:14 +0200 Subject: [PATCH 3/3] test: restore s3 pytest marker dropped in error The previous commit removed the `s3` marker from pyproject, but it is still applied dynamically to doc-example tests (e.g. the `markers="s3"` block in docs/quick-start.md, via getattr(pytest.mark, name) in tests/test_docs.py). Under `--strict-markers` the unknown mark is escalated to a collection error, breaking the doctests, py=3.12, and "Test complete" CI jobs. The `asyncio` marker removal is kept since pytest-asyncio's auto mode registers that marker itself. Co-Authored-By: Claude Opus 4.8 (1M context) --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 7b60e5dd51..02e66c67e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -460,6 +460,7 @@ filterwarnings = [ ] markers = [ "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", ]