Repository: dask/dask
Issue category: Feature Request

Issue:
`array.broadcast_shapes` to return a tuple of `int`, not a tuple of NumPy scalars
<!-- Please do a quick search of existing issues to make sure that this has not been asked before. -->

Before NumPy v2, the `repr` of NumPy scalars returned a plain number. This changed in [NEP 51](https://numpy.org/neps/nep-0051-scalar-representation.html), which changes how the result of `broadcast_shapes()` is printed:

- Before: `(240, 37, 49)`
- After: `(np.int64(240), np.int64(37), np.int64(49))`

There is no functional difference here, but it is much less intuitive to read - especially problematic for documentation/notebooks.

What does everyone think of adding a line into `broadcast_shapes` to ensure that only plain integers are returned? Would this have any unintended consequences? Many thanks.


Hints:
I don't think that we want to deviate from numpy here
> I don't think that we want to deviate from numpy here

Thanks!

I realise I should have compared the behaviour before posting, sorry. Anyway, I can now confirm that Dask is deviating from NumPy:

```python
from dask import array as da
import numpy as np

shapes = [(1, 2), (3, 1), (3, 2)]
from_numpy = np.broadcast_shapes(*shapes)
from_dask = da.core.broadcast_shapes(*shapes)

print(from_numpy)
print(from_dask)
```

```
(3, 2)
(np.int64(3), np.int64(2))
```
Thanks! The change you are proposing makes sense then
I will have a go at a PR

Patch:
diff --git a/dask/array/core.py b/dask/array/core.py
index 7d4f023fa61..faedbb6ef3c 100644
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -4795,7 +4795,7 @@ def broadcast_shapes(*shapes):
         if np.isnan(sizes).any():
             dim = np.nan
         else:
-            dim = 0 if 0 in sizes else np.max(sizes)
+            dim = 0 if 0 in sizes else np.max(sizes).item()
         if any(i not in [-1, 0, 1, dim] and not np.isnan(i) for i in sizes):
             raise ValueError(
                 "operands could not be broadcast together with "


Test patch:
diff --git a/dask/array/tests/test_array_core.py b/dask/array/tests/test_array_core.py
index 7d3e98558c2..121f8a69896 100644
--- a/dask/array/tests/test_array_core.py
+++ b/dask/array/tests/test_array_core.py
@@ -10,6 +10,7 @@
 
 np = pytest.importorskip("numpy")
 
+import itertools
 import math
 import operator
 import os
@@ -871,6 +872,10 @@ def test_broadcast_shapes():
     assert (3, 4) == broadcast_shapes((3, 1), (1, 4), (4,))
     assert (5, 6, 7, 3, 4) == broadcast_shapes((3, 1), (), (5, 6, 7, 1, 4))
 
+    assert all(
+        isinstance(i, int) for i in itertools.chain(*broadcast_shapes([(1, 2), (3, 1)]))
+    )
+
     pytest.raises(ValueError, lambda: broadcast_shapes((3,), (3, 4)))
     pytest.raises(ValueError, lambda: broadcast_shapes((2, 3), (2, 3, 1)))
     pytest.raises(ValueError, lambda: broadcast_shapes((2, 3), (1, np.nan)))