Repository: pydata/xarray

Issue:
Doctest failing with numpy 2.1.3
### What happened?

Yesterday the doctest started to pull in numpy 2.1.3 (before 2.0.2) and NamedArray aggregations started to fail, returning a scalar instead of an array.

Working: https://github.com/pydata/xarray/actions/runs/13037739319/job/36372249466
Breaking: https://github.com/pydata/xarray/actions/runs/13044017287/job/36391424586

The same still works with DataArray returning an array.

That's a release blocker for #10002.




### What did you expect to happen?

Doctest should run.

### Minimal Complete Verifiable Example

```Python
import numpy as np
from xarray.namedarray.core import NamedArray
na = NamedArray("x", np.array([True, True, True, True, True, False], dtype=bool))
out = na.all()
```

### MVCE confirmation

- [ ] Minimal example — the example is as focused as reasonably possible to demonstrate the underlying issue in xarray.
- [ ] Complete example — the example is self-contained, including all data and the text of any traceback.
- [ ] Verifiable example — the example copy & pastes into an IPython prompt or [Binder notebook](https://mybinder.org/v2/gh/pydata/xarray/main?urlpath=lab/tree/doc/examples/blank_template.ipynb), returning the result.
- [ ] New issue — a search of GitHub Issues suggests this is not a duplicate.
- [ ] Recent environment — the issue occurs with the latest version of xarray and its dependencies.

### Relevant log output

```Python
_____ [doctest] xarray.namedarray._aggregations.NamedArrayAggregations.all _____
113         --------
114         >>> from xarray.namedarray.core import NamedArray
115         >>> na = NamedArray(
116         ...     "x", np.array([True, True, True, True, True, False], dtype=bool)
117         ... )
118         >>> na
119         <xarray.NamedArray (x: 6)> Size: 6B
120         array([ True,  True,  True,  True,  True, False])
121 
122         >>> na.all()
Expected:
    <xarray.NamedArray ()> Size: 1B
    array(False)
Got:
    <xarray.NamedArray ()> Size: 1B
    np.False_
```

### Anything else we need to know?

_No response_

### Environment

<details>
INSTALLED VERSIONS
------------------
commit: 151b89acf0d228aea32734369487062cf3cf8312
python: 3.12.8 | packaged by conda-forge | (main, Dec  5 2024, 14:24:40) [GCC 13.3.0]
python-bits: 64
OS: Linux
OS-release: 6.8.0-1020-azure
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: C.UTF-8
LOCALE: ('C', 'UTF-8')
libhdf5: 1.14.4
libnetcdf: 4.9.2

xarray: 2025.1.2.dev28+g151b89ac
pandas: 2.2.3
numpy: 2.1.3
scipy: 1.15.1
netCDF4: 1.7.2
pydap: 3.5.3
h5netcdf: 1.5.0
h5py: 3.12.1
zarr: 3.0.1
cftime: 1.6.4
nc_time_axis: 1.4.1
iris: 3.11.0
bottleneck: 1.4.2
dask: 2025.1.0
distributed: 2025.1.0
matplotlib: 3.10.0
cartopy: 0.24.0
seaborn: 0.13.2
numbagg: 0.8.2
fsspec: 2024.12.0
cupy: None
pint: None
sparse: 0.15.5
flox: 0.9.15
numpy_groupies: 0.11.2
setuptools: 75.8.0
pip: 25.0
conda: None
pytest: 8.3.4
mypy: None
IPython: None
sphinx: None


</details>


Discussion:
kmuehlbauer: Toggling CI 
kmuehlbauer: @keewis The [skip-ci] prevents the CI from running. And the other runs haven been canceled by this commit. Can you push another commit to get CI running again?
kmuehlbauer: @keewis mypy is complaining about some:

```
xarray/tests/test_namedarray.py: note: In member "test_aggregation" of class "TestNamedArray":
xarray/tests/test_namedarray.py:595: error: Need type annotation for "x"  [var-annotated]
```

The other two mypy issues are handled by #10006
kmuehlbauer: Thanks so much @keewis for looking into this! The doctest is fixed! I've followed the suggestion from mypy and added a type-hint. 
keewis: the failing `mypy` CI (unused ignores) is unrelated, so let's merge this

Patch:
diff --git a/doc/whats-new.rst b/doc/whats-new.rst
index 76ed4c43..c76f3800 100644
--- a/doc/whats-new.rst
+++ b/doc/whats-new.rst
@@ -106,6 +106,8 @@ Bug fixes
   By `Kai Mühlbauer <https://github.com/kmuehlbauer>`_.
 - Fix weighted ``polyfit`` for arrays with more than two dimensions (:issue:`9972`, :pull:`9974`).
   By `Mattia Almansi <https://github.com/malmans2>`_.
+- Cast ``numpy`` scalars to arrays in :py:meth:`NamedArray.from_arrays` (:issue:`10005`, :pull:`10008`)
+  By `Justus Magin <https://github.com/keewis>`_.
 
 Documentation
 ~~~~~~~~~~~~~
diff --git a/xarray/namedarray/core.py b/xarray/namedarray/core.py
index 683a1266..cdf9eab5 100644
--- a/xarray/namedarray/core.py
+++ b/xarray/namedarray/core.py
@@ -205,7 +205,7 @@ def from_array(
 
         return NamedArray(dims, data, attrs)
 
-    if isinstance(data, _arrayfunction_or_api):
+    if isinstance(data, _arrayfunction_or_api) and not isinstance(data, np.generic):
         return NamedArray(dims, data, attrs)
 
     if isinstance(data, tuple):


Test patch:
diff --git a/xarray/tests/test_namedarray.py b/xarray/tests/test_namedarray.py
index 7bd2c3be..537cd824 100644
--- a/xarray/tests/test_namedarray.py
+++ b/xarray/tests/test_namedarray.py
@@ -591,6 +591,13 @@ class TestNamedArray(NamedArraySubclassobjects):
         with pytest.warns(UserWarning, match="Duplicate dimension names"):
             NamedArray(("x", "x"), np.arange(4).reshape(2, 2))
 
+    def test_aggregation(self) -> None:
+        x: NamedArray[Any, np.dtype[np.int64]]
+        x = NamedArray(("x", "y"), np.arange(4).reshape(2, 2))
+
+        result = x.sum()
+        assert isinstance(result.data, np.ndarray)
+
 
 def test_repr() -> None:
     x: NamedArray[Any, np.dtype[np.uint64]]