From 845c3ceb26d1b8e79cce9495611300743ae77442 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Fri, 12 Jun 2026 12:47:55 +1200 Subject: [PATCH 1/5] Use to_numpy in ImplicitToExplicitIndexingAdapter.__array__ method Fixes `TypeError: Implicit conversion to a NumPy array is not allowed. Please use `.get()` to construct a NumPy array explicitly` when using a backend engine that loads data onto CuPy, but indexes should stay as NumPy. --- xarray/core/indexing.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py index bb12704e55c..6780e77d9e4 100644 --- a/xarray/core/indexing.py +++ b/xarray/core/indexing.py @@ -35,7 +35,12 @@ to_0d_array, ) from xarray.namedarray.parallelcompat import get_chunked_array_type -from xarray.namedarray.pycompat import array_type, integer_types, is_chunked_array +from xarray.namedarray.pycompat import ( + array_type, + integer_types, + is_chunked_array, + to_numpy, +) if TYPE_CHECKING: from xarray.core.extension_array import PandasExtensionArray @@ -683,9 +688,9 @@ def __array__( self, dtype: DTypeLike | None = None, /, *, copy: bool | None = None ) -> np.ndarray: if Version(np.__version__) >= Version("2.0.0"): - return np.asarray(self.get_duck_array(), dtype=dtype, copy=copy) + return to_numpy(self.get_duck_array(), dtype=dtype, copy=copy) else: - return np.asarray(self.get_duck_array(), dtype=dtype) + return to_numpy(self.get_duck_array(), dtype=dtype) def get_duck_array(self): return self.array.get_duck_array() From 26c83eb5cce0a4275946b9c3094e3b5a1b9feb95 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:05:22 +1200 Subject: [PATCH 2/5] Add changelog entry for bugfix that solves the TypeError --- doc/whats-new.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/whats-new.rst b/doc/whats-new.rst index c435b9c042a..b033e04687c 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -42,7 +42,9 @@ Bug Fixes - Fix :py:func:`decode_cf` failing on integer-encoded time arrays that contain NaT when running against numpy 2.5+. By `Ian Hunt-Isaak `_. - +- Fix ``TypeError: Implicit conversion to a NumPy array is not allowed`` when trying to + use :py:func:`open_mfdataset` with a backend engine reading to CuPy arrays. + By `Wei Ji Leong `_. Documentation ~~~~~~~~~~~~~ From 81f32c1a85a95f391843327f1fef38f8e7d0bce6 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Fri, 12 Jun 2026 21:03:04 +1200 Subject: [PATCH 3/5] Fix type-hint on kwargs of DuckArrayModule.to_numpy method --- xarray/namedarray/pycompat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/namedarray/pycompat.py b/xarray/namedarray/pycompat.py index 5832f7cc9e7..a192930cea7 100644 --- a/xarray/namedarray/pycompat.py +++ b/xarray/namedarray/pycompat.py @@ -97,7 +97,7 @@ def is_0d_dask_array(x: duckarray[Any, Any]) -> bool: def to_numpy( - data: duckarray[Any, Any], **kwargs: dict[str, Any] + data: duckarray[Any, Any], **kwargs: Any ) -> np.ndarray[Any, np.dtype[Any]]: from xarray.core.indexing import ExplicitlyIndexed from xarray.namedarray.parallelcompat import get_chunked_array_type From 553a0b132ccb599c1492f203683f2c11fba19b81 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Fri, 12 Jun 2026 22:37:41 +1200 Subject: [PATCH 4/5] Test that ImplicitToExplicitIndexingAdapter works with duck arrays Ensure that instance of ImplicitToExplicitIndexingAdapter's __array__ method works on duck arrays, tested by passing it through np.asarray. --- xarray/tests/test_indexing.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xarray/tests/test_indexing.py b/xarray/tests/test_indexing.py index 6b0fcd2f59a..891bbbe2da6 100644 --- a/xarray/tests/test_indexing.py +++ b/xarray/tests/test_indexing.py @@ -902,6 +902,14 @@ def test_implicit_indexing_adapter_copy_on_write() -> None: assert isinstance(implicit[:], indexing.ImplicitToExplicitIndexingAdapter) +def test_implicit_indexing_adapter_duck_array() -> None: + array = DuckArrayWrapper(array=np.arange(10)) + implicit = indexing.ImplicitToExplicitIndexingAdapter( + indexing.ArrayApiIndexingAdapter(array), indexing.BasicIndexer + ) + np.testing.assert_array_equal(np.asarray(implicit), np.arange(10)) + + def test_outer_indexer_consistency_with_broadcast_indexes_vectorized() -> None: def nonzero(x): if isinstance(x, np.ndarray) and x.dtype.kind == "b": From 0c405d96b82b1abcdf008a777cfc737a32980852 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Sat, 13 Jun 2026 17:20:18 +1200 Subject: [PATCH 5/5] Wrap to_numpy only around the self.get_duck_array() part So that the dtype and copy arguments are handled by np.asarray. --- xarray/core/indexing.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py index 6780e77d9e4..7884c7bd74a 100644 --- a/xarray/core/indexing.py +++ b/xarray/core/indexing.py @@ -688,9 +688,10 @@ def __array__( self, dtype: DTypeLike | None = None, /, *, copy: bool | None = None ) -> np.ndarray: if Version(np.__version__) >= Version("2.0.0"): - return to_numpy(self.get_duck_array(), dtype=dtype, copy=copy) + return np.asarray(to_numpy(self.get_duck_array()), dtype=dtype, copy=copy) + else: - return to_numpy(self.get_duck_array(), dtype=dtype) + return np.asarray(to_numpy(self.get_duck_array()), dtype=dtype) def get_duck_array(self): return self.array.get_duck_array()