nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: dask/dask
Pull request #11096 (2024-05-04 17:01:26)

update broadcast array for numpy 2
Continuing to make progress towards NumPy 2 support: #11066 .  In https://github.com/numpy/numpy/pull/25570 NumPy updated a number of return types to tuples in place of lists.  This PR updates broadcast_array to return tuples if using numpy >= 2

github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     15 files  ±0       15 suites  ±0   3h 20m 54s :stopwatch: - 4m 45s
 13 121 tests ±0   11 730 :white_check_mark: ±0     931 :zzz: ±0  460 :x: ±0 
162 468 runs  ±0  141 923 :white_check_mark: +1  20 085 :zzz:  - 1  460 :x: ±0 

For more details on these failures, see [this check](https://github.com/dask/dask/runs/24589261689).

Results for commit af965a87. ± Comparison against base commit 067c668a.

[test-results]:data:application/gzip;base64,H4sIACxxNmYC/1XMTQ7CIBCG4asY1i6GgaHgZcxYSkLsj6FlZby7tNqiy++ZyfsUIfbdLC4nSeeTmHNc6vI58RKncd0IpAuV67LdlUS57+uc23ZF2SioeI+Pgk7Vv8CxL6RN/epSmlKxVVIet7ZBbex3H20tHaoDP20EsLTbX3yT33Y7DUNcyhAcnCG2jVMByWDDFsizBo/EitErAHI3x+L1BvjWf4kdAQAA


Patch:
diff --git a/dask/array/core.py b/dask/array/core.py
index 74c11f76d..87ebb5bd3 100644
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -42,7 +42,7 @@ from dask.array.dispatch import (  # noqa: F401
     einsum_lookup,
     tensordot_lookup,
 )
-from dask.array.numpy_compat import _Recurser
+from dask.array.numpy_compat import NUMPY_GE_200, _Recurser
 from dask.array.slicing import replace_ellipsis, setitem_array, slice_array
 from dask.base import (
     DaskMethodsMixin,
@@ -5035,7 +5035,10 @@ def broadcast_arrays(*args, subok=False):
     shape = broadcast_shapes(*(e.shape for e in args))
     chunks = broadcast_chunks(*(e.chunks for e in args))
 
-    result = [broadcast_to(e, shape=shape, chunks=chunks) for e in args]
+    if NUMPY_GE_200:
+        result = tuple(broadcast_to(e, shape=shape, chunks=chunks) for e in args)
+    else:
+        result = [broadcast_to(e, shape=shape, chunks=chunks) for e in args]
 
     return result
 


Test patch:
diff --git a/dask/array/tests/test_array_core.py b/dask/array/tests/test_array_core.py
index 68aa57410..842090546 100644
--- a/dask/array/tests/test_array_core.py
+++ b/dask/array/tests/test_array_core.py
@@ -1108,7 +1108,7 @@ def test_broadcast_arrays():
     a_r = np.broadcast_arrays(a_0, a_1)
     d_r = da.broadcast_arrays(d_a_0, d_a_1)
 
-    assert isinstance(d_r, list)
+    assert isinstance(d_r, (list, tuple))
     assert len(a_r) == len(d_r)
 
     for e_a_r, e_d_r in zip(a_r, d_r):
Repository: dask/dask
Pull request #11106 (2024-05-07 16:32:44)

``meshgrid`` and ``atleast_*d`` NumPy 2 updates
We now return tuples of array instead of lists of arrays to match NumPy 


Patch:
diff --git a/dask/array/creation.py b/dask/array/creation.py
index aa32b1a51..37cbb3008 100644
--- a/dask/array/creation.py
+++ b/dask/array/creation.py
@@ -22,7 +22,7 @@ from dask.array.core import (
     normalize_chunks,
     stack,
 )
-from dask.array.numpy_compat import AxisError
+from dask.array.numpy_compat import NUMPY_GE_200, AxisError
 from dask.array.ufunc import greater_equal, rint
 from dask.array.utils import meta_from_array
 from dask.array.wrap import empty, full, ones, zeros
@@ -501,9 +501,10 @@ def meshgrid(*xi, sparse=False, indexing="xy", **kwargs):
         grid = broadcast_arrays(*grid)
 
     if indexing == "xy" and len(xi) > 1:
-        grid[0], grid[1] = grid[1], grid[0]
+        grid = (grid[1], grid[0], *grid[2:])
 
-    return grid
+    out_type = tuple if NUMPY_GE_200 else list
+    return out_type(grid)
 
 
 def indices(dimensions, dtype=int, chunks="auto"):
diff --git a/dask/array/routines.py b/dask/array/routines.py
index fc118fa89..38fafa6da 100644
--- a/dask/array/routines.py
+++ b/dask/array/routines.py
@@ -83,6 +83,8 @@ def atleast_3d(*arys):
     if len(new_arys) == 1:
         return new_arys[0]
     else:
+        if NUMPY_GE_200:
+            new_arys = tuple(new_arys)
         return new_arys
 
 
@@ -101,6 +103,8 @@ def atleast_2d(*arys):
     if len(new_arys) == 1:
         return new_arys[0]
     else:
+        if NUMPY_GE_200:
+            new_arys = tuple(new_arys)
         return new_arys
 
 
@@ -117,6 +121,8 @@ def atleast_1d(*arys):
     if len(new_arys) == 1:
         return new_arys[0]
     else:
+        if NUMPY_GE_200:
+            new_arys = tuple(new_arys)
         return new_arys
 
 


Test patch:
diff --git a/dask/array/tests/test_creation.py b/dask/array/tests/test_creation.py
index 2d338c47b..db11190dd 100644
--- a/dask/array/tests/test_creation.py
+++ b/dask/array/tests/test_creation.py
@@ -381,7 +381,7 @@ def test_meshgrid(shapes, chunks, indexing, sparse):
     r_a = np.meshgrid(*xi_a, indexing=indexing, sparse=sparse)
     r_d = da.meshgrid(*xi_d, indexing=indexing, sparse=sparse)
 
-    assert isinstance(r_d, list)
+    assert type(r_d) is type(r_a)
     assert len(r_a) == len(r_d)
 
     for e_r_a, e_r_d, i in zip(r_a, r_d, do):
Repository: dask/dask
Pull request #11161 (2024-06-04 10:52:11)

Ensure tokenization of memmap doesn't materialize array in memory
- [ ] Closes https://github.com/dask/dask/issues/11152

I don't truly know how to test this well in a way that is not incredibly slow or flaky on CI. I tested it locally and it does not load any data in memory but I am not aware of an API that would allow us to inspect the mmap and I don't think a test that measures RSS is very reliable


github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     15 files  ±0       15 suites  ±0   3h 23m 13s :stopwatch: - 3m 43s
 13 123 tests ±0   12 158 :white_check_mark: ±0     931 :zzz: ±0  34 :x: ±0 
162 520 runs  ±0  142 450 :white_check_mark: +2  20 036 :zzz:  - 2  34 :x: ±0 

For more details on these failures, see [this check](https://github.com/dask/dask/runs/25783099918).

Results for commit 55669566. ± Comparison against base commit 05a04aaf.

[test-results]:data:application/gzip;base64,H4sIAGD5XmYC/03MTQ6DIBCG4asY1l3ADIzSyzRKISH1p0FYNb17pxrRBYv3GfJ9RIijX8W9UebWiLXEfNazpD7HZf43KItMfM3bHRXUfqzFuf2T6U58xTejRVUp9HFkQl3Fp7QkJsmSyrxNExg4uk5r0ObEfRqkRDrsur3Bddot0xQzhzCGyPLrLAAp8H2L1ikvVdAUhoEcopXUBvH9AYDvCPMbAQAA


Patch:
diff --git a/dask/base.py b/dask/base.py
index ec6c49933..7343152c8 100644
--- a/dask/base.py
+++ b/dask/base.py
@@ -5,6 +5,7 @@ import datetime
 import decimal
 import hashlib
 import inspect
+import os
 import pathlib
 import pickle
 import types
@@ -1349,6 +1350,30 @@ def register_pyarrow():
 def register_numpy():
     import numpy as np
 
+    @normalize_token.register(np.memmap)
+    def normalize_mmap(mm):
+        if hasattr(mm, "mode") and getattr(mm, "filename", None):
+            if hasattr(mm.base, "ctypes"):
+                offset = (
+                    mm.ctypes._as_parameter_.value - mm.base.ctypes._as_parameter_.value
+                )
+            else:
+                offset = 0  # root memmap's have mmap object as base
+            if hasattr(
+                mm, "offset"
+            ):  # offset numpy used while opening, and not the offset to the beginning of file
+                offset += mm.offset
+            return (
+                mm.filename,
+                os.path.getmtime(mm.filename),
+                mm.dtype,
+                mm.shape,
+                mm.strides,
+                offset,
+            )
+        else:
+            return normalize_object(mm)
+
     @normalize_token.register(np.ufunc)
     def normalize_ufunc(func):
         try:


Test patch:
diff --git a/dask/tests/test_tokenize.py b/dask/tests/test_tokenize.py
index a7f6060bd..49461e541 100644
--- a/dask/tests/test_tokenize.py
+++ b/dask/tests/test_tokenize.py
@@ -229,8 +229,7 @@ def test_tokenize_numpy_memmap():
         z = check_tokenize(np.load(fn, mmap_mode="r"))
 
     assert check_tokenize(x1) == check_tokenize(x2)
-    # Memory maps should behave similar to ordinary arrays
-    assert y == z
+    assert y != z
 
     with tmpfile(".npy") as fn:
         x = np.random.normal(size=(10, 10))
Repository: dask/dask
Pull request #11231 (2024-07-17 08:04:09)

Ensure that dask expr DataFrames are optimized when put into delayed
- [ ] Closes #xxxx
- [ ] Tests added / passed
- [ ] Passes `pre-commit run --all-files`


github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     15 files  ± 0       15 suites  ±0   3h 24m 50s :stopwatch: - 1m 8s
 13 128 tests + 1   12 012 :white_check_mark: ±0   1 068 :zzz: ±0  48 :x: +1 
162 783 runs  +12  139 945 :white_check_mark: +8  22 790 :zzz: +3  48 :x: +1 

For more details on these failures, see [this check](https://github.com/dask/dask/runs/27550904766).

Results for commit 79b68900. ± Comparison against base commit 6a04b4ed.

[test-results]:data:application/gzip;base64,H4sIAIuCl2YC/1WMyw7CIBBFf6Vh7QKG8hh/xgCFhNiHobAy/ru02qLLc+bOeZIQR7+Sa8fEpSNribnRUJLJcZk3BkBaVb3m/c4Z6INva3FuH1EGTd7jY5NUtmEwcayub8antKSqtngq896WoDT/8tnmiL045acNoPB4/Gvv4jftlmmKuQJRaKVGSpXvBeNmcNYyFMEosM7LwQSUUvPAyesNcROjeRwBAAA=


Patch:
diff --git a/dask/delayed.py b/dask/delayed.py
index 350e89fbf..1ff6a2dba 100644
--- a/dask/delayed.py
+++ b/dask/delayed.py
@@ -95,6 +95,10 @@ def unpack_collections(expr):
         return expr._key, (expr,)
 
     if is_dask_collection(expr):
+        if hasattr(expr, "optimize"):
+            # Optimize dask-expr collections
+            expr = expr.optimize()
+
         finalized = finalize(expr)
         return finalized._key, (finalized,)
 


Test patch:
diff --git a/dask/dataframe/tests/test_dataframe.py b/dask/dataframe/tests/test_dataframe.py
index a9a77bdf1..fb56de2d1 100644
--- a/dask/dataframe/tests/test_dataframe.py
+++ b/dask/dataframe/tests/test_dataframe.py
@@ -6316,3 +6316,23 @@ def test_query_planning_config_warns():
         expect = "enabled" if dd.DASK_EXPR_ENABLED else "disabled"
         with pytest.warns(match=f"query planning is already {expect}"):
             dd._dask_expr_enabled()
+
+
+def test_dataframe_into_delayed():
+    if not DASK_EXPR_ENABLED:
+        pytest.skip("Only relevant for dask.expr")
+
+    pdf = pd.DataFrame({"a": [1, 2, 3], "b": 1})
+    df = dd.from_pandas(pdf, npartitions=2)
+
+    def test_func(df):
+        return df.sum().sum()
+
+    def delayed_func(i):
+        # sanity check
+        assert i.sum() == 6
+
+    df = df[["a"]].map_partitions(test_func, meta=(None, int))
+    result = delayed(delayed_func)(df)
+    assert sum(map(len, result.dask.layers.values())) == 6
+    result.compute()
Repository: dask/dask
Pull request #11429 (2024-10-15 09:59:45)

Task spec: ensure kwargs can have dependencies


Patch:
diff --git a/dask/_task_spec.py b/dask/_task_spec.py
index 695acdbd8..792df54f6 100644
--- a/dask/_task_spec.py
+++ b/dask/_task_spec.py
@@ -576,7 +576,7 @@ def _get_dependencies(obj: object) -> set | frozenset:
         if not obj:
             return _no_deps
         return set().union(*map(_get_dependencies, obj.values()))
-    elif isinstance(obj, (list, tuple, frozenset, set)):
+    elif isinstance(obj, Iterable) and not isinstance(obj, str):
         if not obj:
             return _no_deps
         return set().union(*map(_get_dependencies, obj))


Test patch:
diff --git a/dask/tests/test_task_spec.py b/dask/tests/test_task_spec.py
index efa2c5265..b5cef98ad 100644
--- a/dask/tests/test_task_spec.py
+++ b/dask/tests/test_task_spec.py
@@ -341,6 +341,27 @@ def test_runnable_as_kwarg():
     assert t() == "ab3"
 
 
+def test_dependency_as_kwarg():
+    def func_kwarg(a, b, c=""):
+        return a + b + str(c)
+
+    t1 = Task("key-1", sum, [1, 2])
+    t2 = Task(
+        "key-2",
+        func_kwarg,
+        "a",
+        "b",
+        c=t1.ref(),
+    )
+    with pytest.raises(RuntimeError, match="missing"):
+        t2()
+    # It isn't sufficient to raise. We also rely on the attribute being set
+    # properly since distribute will use this to infer actual dependencies The
+    # exception may be raised recursively
+    assert t2.dependencies
+    assert t2({"key-1": t1()}) == "ab3"
+
+
 def test_subgraph_callable():
     def add(a, b):
         return a + b
Repository: dask/dask
Pull request #11432 (2024-10-15 15:28:17)

Task Spec: Ensure arrays are allowed as arguments
This is a follow up to https://github.com/dask/dask/pull/11429

It's not a good idea to allow all iterables in here and since this is a private function it's better to just call it differently.

github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     13 files  ± 0       13 suites  ±0   3h 7m 41s :stopwatch: - 1m 32s
 13 219 tests + 1   12 163 :white_check_mark: +1   1 056 :zzz: ±0  0 :x: ±0 
137 887 runs  +13  118 870 :white_check_mark: +8  19 017 :zzz: +5  0 :x: ±0 

Results for commit 1b1f33be. ± Comparison against base commit 2313fe38.

[test-results]:data:application/gzip;base64,H4sIAPaRDmcC/03Myw6DIBCF4VcxrLtgAEH7Mo1cJiFVabismr57sVp0+X8zOW+CfnaJ3Dvgt46k4vNZtsQp+7BuDUxCpXrN+53B+O9HKsZsyEDyE5/+tSHtZTOc/FyNNnAxhnhILOs+rYZBHd2moRpteEyPFNrjZfrX12UTlsXnGgQ0IOfaoe6Z1VyAMFYhOikGOyrUQk5WSNOTzxdKGdpEGgEAAA==


Patch:
diff --git a/dask/_task_spec.py b/dask/_task_spec.py
index 792df54f6..e37a90e05 100644
--- a/dask/_task_spec.py
+++ b/dask/_task_spec.py
@@ -576,7 +576,7 @@ def _get_dependencies(obj: object) -> set | frozenset:
         if not obj:
             return _no_deps
         return set().union(*map(_get_dependencies, obj.values()))
-    elif isinstance(obj, Iterable) and not isinstance(obj, str):
+    elif isinstance(obj, (list, tuple, frozenset, set)):
         if not obj:
             return _no_deps
         return set().union(*map(_get_dependencies, obj))
@@ -608,7 +608,7 @@ class Task(GraphNode):
         self.kwargs = parse_input(kwargs)
         dependencies: set = set()
         dependencies.update(_get_dependencies(self.args))
-        dependencies.update(_get_dependencies(self.kwargs.values()))
+        dependencies.update(_get_dependencies(tuple(self.kwargs.values())))
         if dependencies:
             self.dependencies = dependencies
         else:


Test patch:
diff --git a/dask/tests/test_task_spec.py b/dask/tests/test_task_spec.py
index 23e8ff57f..da361701e 100644
--- a/dask/tests/test_task_spec.py
+++ b/dask/tests/test_task_spec.py
@@ -13,6 +13,7 @@ from dask._task_spec import (
     DependenciesMapping,
     Task,
     TaskRef,
+    _get_dependencies,
     convert_legacy_graph,
     convert_legacy_task,
     execute_graph,
@@ -362,6 +363,17 @@ def test_dependency_as_kwarg():
     assert t2({"key-1": t1()}) == "ab3"
 
 
+def test_array_as_argument():
+    np = pytest.importorskip("numpy")
+    t = Task("key-1", func, np.array([1, 2]), "b")
+    assert t() == "[1 2]-b"
+
+    # This will **not** work since we do not want to recurse into an array!
+    t2 = Task("key-2", func, np.array([1, t.ref()]), "b")
+    assert t2({"key-1": "foo"}) != "[1 foo]-b"
+    assert not _get_dependencies(np.array([1, t.ref()]))
+
+
 def test_subgraph_callable():
     def add(a, b):
         return a + b
Repository: dask/dask
Pull request #11445 (2024-10-18 15:30:09)

Fix behavior of keys_in_tasks for TaskSpec nodes
This is one of the functions I think I want to get rid off in the future but for now we need it for backwards compat.

This ensures same behavior for legacy and new style tasks

github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     13 files  ± 0       13 suites  ±0   3h 22m 38s :stopwatch: - 4m 46s
 13 237 tests + 1   12 175 :white_check_mark: + 1   1 062 :zzz: ±0  0 :x: ±0 
138 097 runs  +13  119 003 :white_check_mark: +13  19 094 :zzz: ±0  0 :x: ±0 

Results for commit f46e8405. ± Comparison against base commit c76e759a.

[test-results]:data:application/gzip;base64,H4sIAJeHEmcC/03MTQ7CIBCG4as0rF0MhTLgZQwZISH2x1BYGe8utZR2+T4z+T7Mh9Gt7N5xcevYmkM665mjTWGZt+75oAuVa9rvvcCjH2sm2p9wOPEV3huC6pt5G8Zi0MDFuMQqMc/7tAaDtds0NwCiYZ02YORhl+l/X5dpmaaQSjAvldMSBuWkNcjJIgkgjhaFVB6kI/KOtGDfH+ys4nUaAQAA


Patch:
diff --git a/dask/core.py b/dask/core.py
index eb126cea4..afe799207 100644
--- a/dask/core.py
+++ b/dask/core.py
@@ -199,7 +199,7 @@ def keys_in_tasks(keys: Collection[Key], tasks: Iterable[Any], as_list: bool = F
             elif typ is dict:
                 work.extend(w.values())
             elif isinstance(w, GraphNode):
-                ret.extend(w.dependencies)
+                work.extend(w.dependencies)
             else:
                 try:
                     if w in keys:


Test patch:
diff --git a/dask/tests/test_task_spec.py b/dask/tests/test_task_spec.py
index f9c993dec..46c3e6974 100644
--- a/dask/tests/test_task_spec.py
+++ b/dask/tests/test_task_spec.py
@@ -21,7 +21,7 @@ from dask._task_spec import (
     resolve_aliases,
 )
 from dask.base import tokenize
-from dask.core import reverse_dict
+from dask.core import keys_in_tasks, reverse_dict
 from dask.optimization import SubgraphCallable
 from dask.sizeof import sizeof
 
@@ -764,6 +764,24 @@ def test_deterministic_tokenization_respected():
         tokenize(Task("key", func, object()), ensure_deterministic=True)
 
 
+def test_keys_in_tasks():
+    b = Task("b", func, "1", "2")
+    b_legacy = Task("b", func, "1", "2")
+
+    a = Task("a", func, "1", b.ref())
+    a_legacy = (func, "1", "b")
+
+    for task in [a, a_legacy]:
+        assert not keys_in_tasks({"a"}, [task])
+
+        assert keys_in_tasks({"a", "b"}, [task]) == {"b"}
+
+        assert keys_in_tasks({"a", "b", "c"}, [task]) == {"b"}
+
+    for tasks in [[a, b], [a_legacy, b_legacy]]:
+        assert keys_in_tasks({"a", "b"}, tasks) == {"b"}
+
+
 def test_dependencies_mapping_doesnt_mutate_task():
 
     t = Task("key", func, "a", "b")
Repository: dask/dask
Pull request #11446 (2024-10-18 17:25:53)

Avoid rechunking 1D-arrays in cumreduction
Improve performance of 1d arrays, they don't need to be flattened and rechunked.

```python
import dask.array as da

x = da.ones((300_000,))
%timeit da.cumsum(x)
# 5.2 s ± 79.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)  # Main
# 856 μs ± 14.2 μs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)  # With PR
```


Illviljan: Any suggestion how to add a test? I don't know how dask checks for regressions in performance usually.
phofl: You don't have to check for performance, you can look at the graph and check that we don't have any rechunks in there for example
Illviljan: > You don't have to check for performance, you can look at the graph and check that we don't have any rechunks in there for example

Do you have a test in mind I can use as base/copy paste? I'm not used to digging in the graph besides using `.visualize`.
github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     13 files  ± 0       13 suites  ±0   3h 24m 4s :stopwatch: +20s
 13 238 tests + 1   12 175 :white_check_mark: ± 0   1 062 :zzz: ±0  1 :x: +1 
138 108 runs  +11  119 012 :white_check_mark: +11  19 095 :zzz:  - 1  1 :x: +1 

For more details on these failures, see [this check](https://github.com/dask/dask/runs/31748689992).

Results for commit 49e74144. ± Comparison against base commit 017adfb1.

[test-results]:data:application/gzip;base64,H4sIAGuqEmcC/03Myw6DIBCF4VcxrLsYRhCmL9MgYkLqpUFYNX334g1d/t9Mzpf1fnALe1a8flRsST5e1aVgop+ntRGFyJSvcb9jrc9+Lcna7YkreeHbf1aEBov1xg+rFXAhzCELZAlp2qc1B310meYEHAse0wQkT7tNb31ftvM4+piDCXJKcCFMJ5XuqCVsFTeIvbQN6EZLQw4sEPv9AYfHWy4aAQAA

Illviljan: Bump! Anything else to do, @phofl ?

Patch:
diff --git a/dask/array/reductions.py b/dask/array/reductions.py
index 49bbe14d8..8f668815f 100644
--- a/dask/array/reductions.py
+++ b/dask/array/reductions.py
@@ -1539,7 +1539,8 @@ def cumreduction(
         )
 
     if axis is None:
-        x = x.flatten().rechunk(chunks=x.npartitions)
+        if x.ndim > 1:
+            x = x.flatten().rechunk(chunks=x.npartitions)
         axis = 0
     if dtype is None:
         dtype = getattr(func(np.ones((0,), dtype=x.dtype)), "dtype", object)


Test patch:
diff --git a/dask/array/tests/test_reductions.py b/dask/array/tests/test_reductions.py
index 4b1e722ad..e694e27d5 100644
--- a/dask/array/tests/test_reductions.py
+++ b/dask/array/tests/test_reductions.py
@@ -910,6 +910,13 @@ def test_weighted_reduction():
         da.reduction(dx, w_sum, np.sum, weights=[[[2]]])
 
 
+def test_cumreduction_no_rechunk_on_1d_array():
+    x = da.ones((5,))
+    y = da.cumsum(x)
+    no_rechunk = "rechunk" not in str(dict(y.__dask_graph__()))
+    assert no_rechunk
+
+
 @pytest.mark.parametrize("axis", [3, 0, [1, 3]])
 @pytest.mark.parametrize("q", [0.75, [0.75], [0.75, 0.4]])
 @pytest.mark.parametrize("rechunk", [True, False])
Repository: dask/dask
Pull request #11480 (2024-10-31 20:05:26)

Patch auto-chunks calculation for rioxarray
- [ ] Closes #xxxx
- [ ] Tests added / passed
- [ ] Passes `pre-commit run --all-files`

See https://github.com/corteva/rioxarray/pull/820

github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     13 files  ± 0       13 suites  ±0   3h 46m 56s ⏱️ + 1m 29s
 13 256 tests + 1   12 194 ✅ +1   1 062 💤 ±0  0 ❌ ±0 
138 309 runs  +11  119 316 ✅ +8  18 993 💤 +3  0 ❌ ±0 

Results for commit 85333810. ± Comparison against base commit 0cb1cb1f.

[test-results]:data:application/gzip;base64,H4sIAJnsI2cC/03OSw7DIAxF0a1UjDsAOxDczVSJQyTUfCoCo6p7L/mUZHiPpSd/RO8Ht4jHTeH9Jpbk41ldCk3087S1USZTvsb9Drr0c0nMK4Ki6sSXf68oDRTrGz9kkwVcCHM4JKRpn7Yo6egyrQi3B3Y8pi0R/u0yvfV1medx9DGHsBoRrZLAzui6Joamq1smC1XLoDvq28oBgPj+ADSAQXoaAQAA


Patch:
diff --git a/dask/array/core.py b/dask/array/core.py
index eb6f40723..bb2e78e57 100644
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -3223,6 +3223,12 @@ def auto_chunks(chunks, shape, limit, dtype, previous_chunks=None):
     normalize_chunks: for full docstring and parameters
     """
     if previous_chunks is not None:
+        # rioxarray is passing ((1, ), (x,)) for shapes like (100, 5x),
+        # so add this compat code for now
+        # https://github.com/corteva/rioxarray/pull/820
+        previous_chunks = (
+            c[0] if isinstance(c, tuple) and len(c) == 1 else c for c in previous_chunks
+        )
         previous_chunks = _convert_int_chunk_to_tuple(shape, previous_chunks)
     chunks = list(chunks)
 


Test patch:
diff --git a/dask/array/tests/test_array_core.py b/dask/array/tests/test_array_core.py
index 121f8a698..4c6b6dc3b 100644
--- a/dask/array/tests/test_array_core.py
+++ b/dask/array/tests/test_array_core.py
@@ -2913,6 +2913,19 @@ def test_normalize_chunks():
         normalize_chunks(((5,), (5,)), (5,))
 
 
+def test_single_element_tuple():
+    assert normalize_chunks(
+        (100, "auto"), (500, 500_000), dtype=np.int64, previous_chunks=((1,), (500,))
+    ) == (
+        (100,) * 5,
+        (
+            167_500,
+            167_500,
+            165_000,
+        ),
+    )
+
+
 def test_align_chunks_to_previous_chunks():
     chunks = normalize_chunks(
         "auto", shape=(2000,), previous_chunks=(512,), limit="600 B", dtype=np.uint8