diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 5cfec4189b1..5037e4df09e 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -30,6 +30,8 @@ New Features region to write in the original store. Also implement automatic transpose when dimension order does not match the original store. (:issue:`7702`, :issue:`8421`, :pull:`8434`). By `Sam Levang `_. +- Allow the usage of h5py drivers (eg: ros3) via h5netcdf (:pull:`8360`). + By `Ezequiel Cimadevilla `_. Breaking changes ~~~~~~~~~~~~~~~~ diff --git a/xarray/backends/h5netcdf_.py b/xarray/backends/h5netcdf_.py index 19748084625..a68a44b5f6f 100644 --- a/xarray/backends/h5netcdf_.py +++ b/xarray/backends/h5netcdf_.py @@ -140,6 +140,8 @@ def open( invalid_netcdf=None, phony_dims=None, decode_vlen_strings=True, + driver=None, + driver_kwds=None, ): import h5netcdf @@ -161,7 +163,10 @@ def open( kwargs = { "invalid_netcdf": invalid_netcdf, "decode_vlen_strings": decode_vlen_strings, + "driver": driver, } + if driver_kwds is not None: + kwargs.update(driver_kwds) if phony_dims is not None: kwargs["phony_dims"] = phony_dims @@ -397,6 +402,8 @@ def open_dataset( # type: ignore[override] # allow LSP violation, not supporti invalid_netcdf=None, phony_dims=None, decode_vlen_strings=True, + driver=None, + driver_kwds=None, ) -> Dataset: filename_or_obj = _normalize_path(filename_or_obj) store = H5NetCDFStore.open( @@ -407,6 +414,8 @@ def open_dataset( # type: ignore[override] # allow LSP violation, not supporti invalid_netcdf=invalid_netcdf, phony_dims=phony_dims, decode_vlen_strings=decode_vlen_strings, + driver=driver, + driver_kwds=driver_kwds, ) store_entrypoint = StoreBackendEntrypoint() diff --git a/xarray/tests/__init__.py b/xarray/tests/__init__.py index 4f9c188e6a6..fec695f83d7 100644 --- a/xarray/tests/__init__.py +++ b/xarray/tests/__init__.py @@ -94,6 +94,10 @@ def _importorskip( requires_pandas_version_two = pytest.mark.skipif( not has_pandas_version_two, reason="requires pandas 2.0.0" ) +has_h5netcdf_ros3 = _importorskip("h5netcdf", "1.3.0") +requires_h5netcdf_ros3 = pytest.mark.skipif( + not has_h5netcdf_ros3[0], reason="requires h5netcdf 1.3.0" +) # change some global options for tests set_options(warn_for_unclosed_files=True) diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 1c8a24770d7..80b6951dbff 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -69,6 +69,7 @@ requires_dask, requires_fsspec, requires_h5netcdf, + requires_h5netcdf_ros3, requires_iris, requires_netCDF4, requires_pydap, @@ -3448,6 +3449,34 @@ def test_write_inconsistent_chunks(self) -> None: assert actual["y"].encoding["chunksizes"] == (100, 50) +@requires_h5netcdf_ros3 +class TestH5NetCDFDataRos3Driver(TestCommon): + engine: T_NetcdfEngine = "h5netcdf" + test_remote_dataset: str = ( + "https://www.unidata.ucar.edu/software/netcdf/examples/OMI-Aura_L2-example.nc" + ) + + def test_get_variable_list(self) -> None: + with open_dataset( + self.test_remote_dataset, + engine="h5netcdf", + backend_kwargs={"driver": "ros3"}, + ) as actual: + assert "Temperature" in list(actual) + + def test_get_variable_list_empty_driver_kwds(self) -> None: + driver_kwds = { + "secret_id": b"", + "secret_key": b"", + } + backend_kwargs = {"driver": "ros3", "driver_kwds": driver_kwds} + + with open_dataset( + self.test_remote_dataset, engine="h5netcdf", backend_kwargs=backend_kwargs + ) as actual: + assert "Temperature" in list(actual) + + @pytest.fixture(params=["scipy", "netcdf4", "h5netcdf", "pynio", "zarr"]) def readengine(request): return request.param