diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index aa0e59f5ced..7434c646428 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,8 +37,6 @@ jobs: runs-on: ${{ matrix.os }} needs: detect-ci-trigger if: needs.detect-ci-trigger.outputs.triggered == 'false' - env: - ZARR_V3_EXPERIMENTAL_API: 1 defaults: run: shell: bash -l {0} diff --git a/.github/workflows/upstream-dev-ci.yaml b/.github/workflows/upstream-dev-ci.yaml index dd3743d9a96..183eec48547 100644 --- a/.github/workflows/upstream-dev-ci.yaml +++ b/.github/workflows/upstream-dev-ci.yaml @@ -40,8 +40,6 @@ jobs: name: upstream-dev runs-on: ubuntu-latest needs: detect-ci-trigger - env: - ZARR_V3_EXPERIMENTAL_API: 1 if: | always() && ( diff --git a/conftest.py b/conftest.py index 200696431ea..ed197c2bae4 100644 --- a/conftest.py +++ b/conftest.py @@ -41,6 +41,12 @@ def pytest_collection_modifyitems(items): item.add_marker(pytest.mark.mypy) +@pytest.fixture(autouse=True) +def set_zarr_v3_api(monkeypatch): + """Set ZARR_V3_EXPERIMENTAL_API environment variable for all tests.""" + monkeypatch.setenv("ZARR_V3_EXPERIMENTAL_API", "1") + + @pytest.fixture(autouse=True) def add_standard_imports(doctest_namespace, tmpdir): import numpy as np diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 3ed49140a9b..c4292efaf6e 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -168,6 +168,64 @@ def skip_if_zarr_format_2(reason: str): ON_WINDOWS = sys.platform == "win32" default_value = object() + + +def _check_compression_codec_available(codec: str | None) -> bool: + """Check if a compression codec is available in the netCDF4 library. + + Parameters + ---------- + codec : str or None + The compression codec name (e.g., 'zstd', 'blosc_lz', etc.) + + Returns + ------- + bool + True if the codec is available, False otherwise. + """ + if codec is None or codec in ("zlib", "szip"): + # These are standard and should be available + return True + + if not has_netCDF4: + return False + + try: + import os + import tempfile + + import netCDF4 + + # Try to create a file with the compression to test availability + with tempfile.NamedTemporaryFile(suffix=".nc", delete=False) as tmp: + tmp_path = tmp.name + + try: + nc = netCDF4.Dataset(tmp_path, "w", format="NETCDF4") + nc.createDimension("x", 10) + + # Attempt to create a variable with the compression + if codec and codec.startswith("blosc"): + nc.createVariable( + "test", "f4", ("x",), compression=codec, blosc_shuffle=1 + ) + else: + nc.createVariable("test", "f4", ("x",), compression=codec) + + nc.close() + os.unlink(tmp_path) + return True + except (RuntimeError, netCDF4.NetCDF4MissingFeatureException): + # Codec not available + if os.path.exists(tmp_path): + with contextlib.suppress(OSError): + os.unlink(tmp_path) + return False + except Exception: + # Any other error, assume codec is not available + return False + + dask_array_type = array_type("dask") if TYPE_CHECKING: @@ -2263,12 +2321,48 @@ def test_setncattr_string(self) -> None: None, "zlib", "szip", - "zstd", - "blosc_lz", - "blosc_lz4", - "blosc_lz4hc", - "blosc_zlib", - "blosc_zstd", + pytest.param( + "zstd", + marks=pytest.mark.xfail( + not _check_compression_codec_available("zstd"), + reason="zstd codec not available in netCDF4 installation", + ), + ), + pytest.param( + "blosc_lz", + marks=pytest.mark.xfail( + not _check_compression_codec_available("blosc_lz"), + reason="blosc_lz codec not available in netCDF4 installation", + ), + ), + pytest.param( + "blosc_lz4", + marks=pytest.mark.xfail( + not _check_compression_codec_available("blosc_lz4"), + reason="blosc_lz4 codec not available in netCDF4 installation", + ), + ), + pytest.param( + "blosc_lz4hc", + marks=pytest.mark.xfail( + not _check_compression_codec_available("blosc_lz4hc"), + reason="blosc_lz4hc codec not available in netCDF4 installation", + ), + ), + pytest.param( + "blosc_zlib", + marks=pytest.mark.xfail( + not _check_compression_codec_available("blosc_zlib"), + reason="blosc_zlib codec not available in netCDF4 installation", + ), + ), + pytest.param( + "blosc_zstd", + marks=pytest.mark.xfail( + not _check_compression_codec_available("blosc_zstd"), + reason="blosc_zstd codec not available in netCDF4 installation", + ), + ), ], ) @requires_netCDF4_1_6_2_or_above