From fb612b12a6f5792e4ac64ea680c6a6ee3cced8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=BChlbauer?= Date: Tue, 21 Oct 2025 11:14:16 +0200 Subject: [PATCH 1/6] fix indexing with empty arrays for OUTER_1VECTOR --- xarray/core/indexing.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py index e238599c3f8..e40226793a2 100644 --- a/xarray/core/indexing.py +++ b/xarray/core/indexing.py @@ -1366,7 +1366,7 @@ def _decompose_outer_indexer( gains = [ ( (np.max(k) - np.min(k) + 1.0) / len(np.unique(k)) - if isinstance(k, np.ndarray) + if isinstance(k, np.ndarray) and k.size != 0 else 0 ) for k in indexer_elems @@ -1374,7 +1374,11 @@ def _decompose_outer_indexer( array_index = np.argmax(np.array(gains)) if len(gains) > 0 else None for i, (k, s) in enumerate(zip(indexer_elems, shape, strict=False)): - if isinstance(k, np.ndarray) and i != array_index: + if isinstance(k, np.ndarray) and k.size == 0: + # empty np.ndarray key is converted to empty slice + # see https://github.com/pydata/xarray/issues/10867 + backend_indexer.append(slice(0, 0)) + elif isinstance(k, np.ndarray) and i != array_index: # np.ndarray key is converted to slice that covers the entire # entries of this key. backend_indexer.append(slice(np.min(k), np.max(k) + 1)) From e915a1b279ed9d1fa81dcd9230074fb214253494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=BChlbauer?= Date: Tue, 21 Oct 2025 12:22:16 +0200 Subject: [PATCH 2/6] add test --- xarray/tests/test_backends.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 133b71927ea..757765d666f 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -986,6 +986,15 @@ def test_isel_dataarray(self) -> None: actual = on_disk.isel(dim2=on_disk["dim2"] < 3) assert_identical(expected, actual) + def test_empty_isel(self) -> None: + # Make sure isel works lazily with empty indexer. + # GH:issue:10867 + in_memory = xr.Dataset({"a": ("x", np.arange(4))}) + with self.roundtrip(in_memory) as on_disk: + expected = in_memory.isel(x=[]) + actual = on_disk.isel(x=[]) + assert_identical(expected, actual) + def validate_array_type(self, ds): # Make sure that only NumpyIndexingAdapter stores a bare np.ndarray. def find_and_validate_array(obj): From 4366837a8fbaca25696b8ea4b5c534d3146cbf0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=BChlbauer?= Date: Tue, 21 Oct 2025 13:12:04 +0200 Subject: [PATCH 3/6] proper coordinate --- xarray/tests/test_backends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/tests/test_backends.py b/xarray/tests/test_backends.py index 757765d666f..36a1e354d9c 100644 --- a/xarray/tests/test_backends.py +++ b/xarray/tests/test_backends.py @@ -989,7 +989,7 @@ def test_isel_dataarray(self) -> None: def test_empty_isel(self) -> None: # Make sure isel works lazily with empty indexer. # GH:issue:10867 - in_memory = xr.Dataset({"a": ("x", np.arange(4))}) + in_memory = xr.Dataset({"a": ("x", np.arange(4))}, coords={"x": np.arange(4)}) with self.roundtrip(in_memory) as on_disk: expected = in_memory.isel(x=[]) actual = on_disk.isel(x=[]) From bdfc19645ecd05a9128b5eda40b9f816a1d4b0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=BChlbauer?= Date: Tue, 21 Oct 2025 13:15:53 +0200 Subject: [PATCH 4/6] add whats-new.rst entry --- doc/whats-new.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 7b9b3263a3d..3ee88961e42 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -32,12 +32,13 @@ Bug Fixes ~~~~~~~~~ - Fix h5netcdf backend for format=None, use same rule as netcdf4 backend (:pull:`10859`). By `Kai Mühlbauer `_ - - ``netcdf4`` and ``pydap`` backends now use stricter URL detection to avoid incorrectly claiming remote URLs. The ``pydap`` backend now only claims URLs with explicit DAP protocol indicators (``dap2://`` or ``dap4://`` schemes, or ``/dap2/`` or ``/dap4/`` in the URL path). This prevents both backends from claiming remote Zarr stores and other non-DAP URLs without an explicit ``engine=`` argument. (:pull:`10804`). By `Ian Hunt-Isaak `_. +- Fix indexing with empty selection for OUTER_1VECTOR which now resolves to empty slices (:issue:`10867`, :pull:`10870`). + By By `Kai Mühlbauer `_ Documentation ~~~~~~~~~~~~~ From 449924ce9839a44689bc0e1ee55b687e172f04c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=BChlbauer?= Date: Tue, 21 Oct 2025 13:18:33 +0200 Subject: [PATCH 5/6] fix whats-new.rst entry --- doc/whats-new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 3ee88961e42..5e28ee9a8b5 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -38,7 +38,7 @@ Bug Fixes both backends from claiming remote Zarr stores and other non-DAP URLs without an explicit ``engine=`` argument. (:pull:`10804`). By `Ian Hunt-Isaak `_. - Fix indexing with empty selection for OUTER_1VECTOR which now resolves to empty slices (:issue:`10867`, :pull:`10870`). - By By `Kai Mühlbauer `_ + By `Kai Mühlbauer `_ Documentation ~~~~~~~~~~~~~ From a2f11f92cc217dd19fb6914b0fc0aef1306ca053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20M=C3=BChlbauer?= Date: Tue, 21 Oct 2025 14:17:30 +0200 Subject: [PATCH 6/6] Update doc/whats-new.rst Co-authored-by: Deepak Cherian --- doc/whats-new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index 5e28ee9a8b5..2617dee17bf 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -37,7 +37,7 @@ Bug Fixes (``dap2://`` or ``dap4://`` schemes, or ``/dap2/`` or ``/dap4/`` in the URL path). This prevents both backends from claiming remote Zarr stores and other non-DAP URLs without an explicit ``engine=`` argument. (:pull:`10804`). By `Ian Hunt-Isaak `_. -- Fix indexing with empty selection for OUTER_1VECTOR which now resolves to empty slices (:issue:`10867`, :pull:`10870`). +- Fix indexing with empty arrays for scipy & h5netcdf backends which now resolves to empty slices (:issue:`10867`, :pull:`10870`). By `Kai Mühlbauer `_ Documentation