internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: dask/dask

Issue:
Applying da.std to numpy array yields keyword error
When applying `da.std` to a numpy array it yields a Keyword error, while all other combinations of numpy and dask arrays and functions do work. 

Admittedly this is a bit of pathetic use case / anti-pattern, but should be easy to fix. 

Would there be some more general way to test for this kind of errors?

```python
np.random.seed(10)
npdat = np.random.random(5)
dadat = da.from_array(npdat)
da.std(dadat).compute(), np.std(npdat), np.std(dadat).compute()  # all work
da.std(npdat)
```

> TypeError                                 Traceback (most recent call last)
> <ipython-input-130-a1acaa3fc2bb> in <module>
>       1 np.random.seed(10)
>       2 npdat = np.random.random(5) #+ 1j*np.random.random(5)
> ----> 3 da.std(npdat)
> 
> C:\ProgramData\Anaconda3\lib\site-packages\dask\array\reductions.py in std(a, axis, dtype, keepdims, ddof, split_every, out)
>     820             ddof=ddof,
>     821             split_every=split_every,
> --> 822             out=out,
>     823         )
>     824     )
> 
> TypeError: _var() got an unexpected keyword argument 'split_every'


Discussion:

Resolving patch:
diff --git a/dask/array/reductions.py b/dask/array/reductions.py
--- a/dask/array/reductions.py
+++ b/dask/array/reductions.py
@@ -813,7 +813,8 @@ def nanvar(
 @wraps(chunk.std)
 def std(a, axis=None, dtype=None, keepdims=False, ddof=0, split_every=None, out=None):
     result = sqrt(
-        a.var(
+        var(
+            a,
             axis=axis,
             dtype=dtype,
             keepdims=keepdims,


Test patch:
diff --git a/dask/array/tests/test_reductions.py b/dask/array/tests/test_reductions.py
--- a/dask/array/tests/test_reductions.py
+++ b/dask/array/tests/test_reductions.py
@@ -49,6 +49,9 @@ def test_numel(dtype, keepdims):
 
 def reduction_1d_test(da_func, darr, np_func, narr, use_dtype=True, split_every=True):
     assert_eq(da_func(darr), np_func(narr))
+    assert_eq(
+        da_func(narr), np_func(narr)
+    )  # Ensure Dask reductions work with NumPy arrays
     assert_eq(da_func(darr, keepdims=True), np_func(narr, keepdims=True))
     assert_eq(da_func(darr, axis=()), np_func(narr, axis=()))
     assert same_keys(da_func(darr), da_func(darr))
Repository: dask/dask

Issue:
Fix simple typo: wihout -> without
There is a small typo in dask/dataframe/io/json.py.
Should read `without` rather than `wihout`.




Discussion:

Resolving patch:
diff --git a/dask/dataframe/io/json.py b/dask/dataframe/io/json.py
--- a/dask/dataframe/io/json.py
+++ b/dask/dataframe/io/json.py
@@ -132,7 +132,7 @@ def read_json(
         newline character.
     sample: int
         Number of bytes to pre-load, to provide an empty dataframe structure
-        to any blocks wihout data. Only relevant is using blocksize.
+        to any blocks without data. Only relevant is using blocksize.
     encoding, errors:
         Text conversion, ``see bytes.decode()``
     compression : string or None


Test patch:
Repository: dask/dask

Issue:
Use shallow copies when assigning columns
Currently when we run code like `df["z"] = df.x + df.y` we call `df = df.assign(z=df.x + df.y)`.  However, the latter snippet calls the underlying assign method, which calls `df.copy()` which can be slow.  Instead, it might be nice to do soemthing like the following:

```python
def set_column(df, name, value):
    df = df.copy(deep=False)
    df[name] = value
    return df
```

And then replace the calls to `M.assign` with this.

This is particularly important for cudf, but probably helps pandas performance a bit as well.

We might want to do this for all assign calls, rather than just setitem?  There are some semantic differences in pandas apparently with regards to copying, but because we don't mutate my guess is that we should do this everywhere.  @TomAugspurger ?


Discussion:
Also cc @rjzamora @quasiben and @kkraus14 
>  There are some semantic differences in pandas apparently with regards to copying, but because we don't mutate my guess is that we should do this everywhere.

That's my initial reaction. So this seems like a good change to make.

On this topic, https://github.com/pandas-dev/pandas/issues/29309 may be worth reading through.

The operations

```python
    df = df.copy(deep=False)
    df[name] = value
```

May or may not update the original `df` passed to your `set_column`, depending on if you're updating an existing column and the dtypes of the original and new values. I can prioritize fixing that on the pandas side of things if needed.

Resolving patch:
diff --git a/dask/dataframe/methods.py b/dask/dataframe/methods.py
--- a/dask/dataframe/methods.py
+++ b/dask/dataframe/methods.py
@@ -257,8 +257,14 @@ def cummax_aggregate(x, y):
 
 
 def assign(df, *pairs):
-    kwargs = dict(partition(2, pairs))
-    return df.assign(**kwargs)
+    # Only deep copy when updating an element
+    # (to avoid modifying the original)
+    pairs = dict(partition(2, pairs))
+    deep = bool(set(pairs) & set(df.columns))
+    df = df.copy(deep=bool(deep))
+    for name, val in pairs.items():
+        df[name] = val
+    return df
 
 
 def unique(x, series_name=None):


Test patch:
Repository: dask/dask

Issue:
Bag repartition can increase, docstring implies otherwise
The original issue https://github.com/dask/dask/issues/1699 solves being able to repartition a bag into more partitions (useful after a flatten() for example).

However, the doc string wasn't updated as part of the PR - it says: "Coalesce bag into fewer partitions."

I would suggest updating it to "Change number of partitions of bag". Happy to do a PR for it.

A similar fix was applied to dataframe for https://github.com/dask/dask/issues/3439


Discussion:
That would be great.  Thank you Adam

On Fri, Nov 8, 2019 at 6:12 AM Adam Faulconbridge <notifications@github.com>
wrote:

> The original issue #1699 <https://github.com/dask/dask/issues/1699>
> solves being able to repartition a bag into more partitions (useful after a
> flatten() for example).
>
> However, the doc string wasn't updated as part of the PR - it says:
> "Coalesce bag into fewer partitions."
>
> I would suggest updating it to "Change number of partitions of bag". Happy
> to do a PR for it.
>
> A similar fix was applied to dataframe for #3439
> <https://github.com/dask/dask/issues/3439>
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/dask/dask/issues/5570?email_source=notifications&email_token=AACKZTAAOSNFFDF3TM2XG6DQSVXUNA5CNFSM4JKXXUG2YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HX7D4HA>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AACKZTCCGTBLMPIARI2XMCLQSVXUNANCNFSM4JKXXUGQ>
> .
>


Resolving patch:
diff --git a/dask/bag/core.py b/dask/bag/core.py
--- a/dask/bag/core.py
+++ b/dask/bag/core.py
@@ -1601,7 +1601,10 @@ def to_delayed(self, optimize_graph=True):
         return [Delayed(k, dsk) for k in keys]
 
     def repartition(self, npartitions):
-        """ Coalesce bag into fewer partitions.
+        """ Changes the number of partitions of the bag.
+
+        This can be used to reduce or increase the number of partitions
+        of the bag.
 
         Examples
         --------


Test patch:
Repository: dask/dask

Issue:
Error when tokenizing pandas objects if dask[dataframe] not installed
I am using code that uses distributed but doesn't rely on dask dataframes.  In the dask 2.10 releases I am encountering an error when dask is tokenizing pandas dataframes.

Example code:
Install dask, distributed, and pandas into a clean environment:
```bash
pip install dask distributed pandas
```
Attempt to tokenize a pandas object:
```python
import pandas as pd
from dask.base import tokenize


df = pd.DataFrame([[0, 1], [1, 0]])
tokenize(df)
```
This raises
```python-traceback
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "~/featuretools/daskenv/lib/python3.6/site-packages/dask/base.py", line 651, in tokenize
    return md5(str(tuple(map(normalize_token, args))).encode()).hexdigest()
  File "~/featuretools/daskenv/lib/python3.6/site-packages/dask/utils.py", line 504, in __call__
    meth = self.dispatch(type(arg))
  File "~/featuretools/daskenv/lib/python3.6/site-packages/dask/utils.py", line 491, in dispatch
    register()
  File "~/featuretools/daskenv/lib/python3.6/site-packages/dask/base.py", line 742, in register_pandas
    from dask.dataframe._compat import PANDAS_GT_0240
  File "~/featuretools/daskenv/lib/python3.6/site-packages/dask/dataframe/__init__.py", line 55, in <module>
    raise ImportError(str(e) + "\n\n" + msg)
ImportError: fsspec is required to use any file-system functionality. Please install using
conda install -c conda-forge 'fsspec>=0.3.3'
or
pip install 'fsspec>=0.3.3'

Dask dataframe requirements are not installed.

Please either conda or pip install as follows:

  conda install dask                     # either conda install
  pip install dask[dataframe] --upgrade  # or pip install
```


Discussion:

Resolving patch:
diff --git a/dask/base.py b/dask/base.py
--- a/dask/base.py
+++ b/dask/base.py
@@ -8,6 +8,7 @@
 import os
 import threading
 import uuid
+from distutils.version import LooseVersion
 
 from toolz import merge, groupby, curry, identity
 from toolz.functoolz import Compose
@@ -739,7 +740,10 @@ def _normalize_function(func):
 @normalize_token.register_lazy("pandas")
 def register_pandas():
     import pandas as pd
-    from dask.dataframe._compat import PANDAS_GT_0240
+
+    # Intentionally not importing PANDAS_GT_0240 from dask.dataframe._compat
+    # to avoid ImportErrors from extra dependencies
+    PANDAS_GT_0240 = LooseVersion(pd.__version__) >= LooseVersion("0.24.0")
 
     @normalize_token.register(pd.Index)
     def normalize_index(ind):


Test patch:
Repository: dask/dask

Issue:
normalize_token pickles data of literal
While investigating a slow call to `tokenize` I discovered that when a `literal` is passed to a function that tokenizes args, it ends up pickling the quoted data instead of recursively normalising it. This is because there is no normalizer registered for `literal`, so it goes down the generic path for callables, which uses pickle.

Example:
```python
from dask.base import normalize_token
from dask.core import literal

d = {'a': [1, 2], 'b': [3]}
print(normalize_token(d))
print(normalize_token(literal(d)))
```

Output:
```
('list', [('tuple', ['a', ('list', [1, 2])]), ('tuple', ['b', ('list', [3])])])
b'cdask.core\nliteral\np0\n((dp1\nVa\np2\n(lp3\nL1L\naL2L\nasVb\np4\n(lp5\nL3L\nastp6\nRp7\n.'
```

This is on current master.


Discussion:

Resolving patch:
diff --git a/dask/base.py b/dask/base.py
--- a/dask/base.py
+++ b/dask/base.py
@@ -15,7 +15,7 @@
 
 from .compatibility import is_dataclass, dataclass_fields
 from .context import thread_state
-from .core import flatten, quote, get as simple_get
+from .core import flatten, quote, get as simple_get, literal
 from .hashing import hash_buffer_hex
 from .utils import Dispatch, ensure_dict, apply
 from . import config, local, threaded
@@ -678,6 +678,11 @@ def normalize_seq(seq):
     return type(seq).__name__, list(map(normalize_token, seq))
 
 
+@normalize_token.register(literal)
+def normalize_literal(lit):
+    return "literal", normalize_token(lit())
+
+
 @normalize_token.register(object)
 def normalize_object(o):
     method = getattr(o, "__dask_tokenize__", None)


Test patch:
diff --git a/dask/tests/test_base.py b/dask/tests/test_base.py
--- a/dask/tests/test_base.py
+++ b/dask/tests/test_base.py
@@ -25,6 +25,7 @@
     named_schedulers,
     get_scheduler,
 )
+from dask.core import literal
 from dask.delayed import Delayed
 from dask.utils import tmpdir, tmpfile, ignoring
 from dask.utils_test import inc, dec
@@ -406,6 +407,10 @@ def test_tokenize_base_types(x):
     assert tokenize(x) == tokenize(x), x
 
 
+def test_tokenize_literal():
+    assert tokenize(literal(["x", 1])) == tokenize(literal(["x", 1]))
+
+
 @pytest.mark.skipif("not np")
 @pytest.mark.filterwarnings("ignore:the matrix:PendingDeprecationWarning")
 def test_tokenize_numpy_matrix():
Repository: dask/dask

Issue:
dask.core.quote does not quote dicts
It seems that dask now recurses into dicts stored within a graph to find keys (I'm not quite sure when that came in: #1748 proposed it but was never merged). However, `quote` doesn't take that into account.

```python3
from dask import core
core.get({"x": quote({"a": "x"})}, "x")
```

Produces
```
RuntimeError: Cycle detected in Dask: x->x
```

I'll make a PR to fix it.


Discussion:

Resolving patch:
diff --git a/dask/core.py b/dask/core.py
--- a/dask/core.py
+++ b/dask/core.py
@@ -463,6 +463,6 @@ def quote(x):
     >>> quote((add, 1, 2))  # doctest: +SKIP
     (literal<type=tuple>,)
     """
-    if istask(x) or type(x) is list:
+    if istask(x) or type(x) is list or type(x) is dict:
         return (literal(x),)
     return x


Test patch:
diff --git a/dask/tests/test_core.py b/dask/tests/test_core.py
--- a/dask/tests/test_core.py
+++ b/dask/tests/test_core.py
@@ -250,7 +250,7 @@ def __eq__(self, other):
 
 
 def test_quote():
-    literals = [[1, 2, 3], (add, 1, 2), [1, [2, 3]], (add, 1, (add, 2, 3))]
+    literals = [[1, 2, 3], (add, 1, 2), [1, [2, 3]], (add, 1, (add, 2, 3)), {"x": "x"}]
 
     for l in literals:
         assert core.get({"x": quote(l)}, "x") == l
Repository: dask/dask

Issue:
plan_rechunk sometimes adds a no-op step
I noticed this in production code, but it can be demonstrated by adding a test to `dask/array/tests/test_rechunk.py::test_plan_rechunk`:

```python
    steps = _plan((c, c), (f, f), threshold=1)
    _assert_steps(steps, [(f, f)])
```
The actual plan that's recreated is [(c, c), (f, f)] i.e. the first step is to change nothing.

I'll submit a PR to avoid performing this step.


Discussion:

Resolving patch:
diff --git a/dask/array/rechunk.py b/dask/array/rechunk.py
--- a/dask/array/rechunk.py
+++ b/dask/array/rechunk.py
@@ -511,7 +511,8 @@ def plan_rechunk(
         )
         if (chunks == current_chunks and not first_pass) or chunks == new_chunks:
             break
-        steps.append(chunks)
+        if chunks != current_chunks:
+            steps.append(chunks)
         current_chunks = chunks
         if not memory_limit_hit:
             break


Test patch:
diff --git a/dask/array/tests/test_rechunk.py b/dask/array/tests/test_rechunk.py
--- a/dask/array/tests/test_rechunk.py
+++ b/dask/array/tests/test_rechunk.py
@@ -280,9 +280,13 @@ def test_merge_to_number():
     assert chunks == (9,)
 
 
-def _plan(old_chunks, new_chunks, itemsize=1, block_size_limit=1e7):
+def _plan(old_chunks, new_chunks, itemsize=1, block_size_limit=1e7, threshold=4):
     return plan_rechunk(
-        old_chunks, new_chunks, itemsize=itemsize, block_size_limit=block_size_limit
+        old_chunks,
+        new_chunks,
+        itemsize=itemsize,
+        block_size_limit=block_size_limit,
+        threshold=threshold,
     )
 
 
@@ -326,6 +330,10 @@ def test_plan_rechunk():
     steps = _plan((nc + nf, c + c, c + f), (nc + nf, f + f, c + c))
     _assert_steps(steps, steps)
 
+    # Regression test for #5908
+    steps = _plan((c, c), (f, f), threshold=1)
+    _assert_steps(steps, [(f, f)])
+
     # Just at the memory limit => an intermediate is used
     steps = _plan((f, c), (c, f), block_size_limit=400)
     _assert_steps(steps, [(c, c), (c, f)])
Repository: dask/dask

Issue:
Dask array repr raises error when name is non-zero int
If the name of a dask array is a non-zero integer, the `__repr__` method raises an error. For example:

```python
import dask.array as da

print(da.ones((10, 10), chunks=(5, 5), dtype='i4', name=1))
```

Raises the following error:

```python-traceback
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-df280c9cbc39> in <module>
      1 import dask.array as da
      2 
----> 3 print(da.ones((10, 10), chunks=(5, 5), dtype='i4', name=1))

~/dask/dask/array/core.py in __repr__(self)
   1241         """
   1242         chunksize = str(self.chunksize)
-> 1243         name = self.name.rsplit("-", 1)[0]
   1244         return "dask.array<%s, shape=%s, dtype=%s, chunksize=%s, chunktype=%s.%s>" % (
   1245             name,

AttributeError: 'int' object has no attribute 'rsplit'
```


Discussion:

Resolving patch:
diff --git a/dask/array/core.py b/dask/array/core.py
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -1041,7 +1041,7 @@ def __new__(cls, dask, name, chunks, dtype=None, meta=None, shape=None):
         if not isinstance(dask, HighLevelGraph):
             dask = HighLevelGraph.from_collections(name, dask, dependencies=())
         self.dask = dask
-        self.name = name
+        self.name = str(name)
         meta = meta_from_array(meta, dtype=dtype)
 
         if (


Test patch:
Repository: dask/dask

Issue:
Match NumPy signature change for unravel_index
NumPy changed the signature of unravel_index from 

```python
def unravel_index(indices, dims, order='C'):
```

to

```python
def unravel_index(indices, shape, order='C'):
```

I spent a few minutes trying to get a version that worked with both older and newer versions of NumPy, but didn't finish it.

Split from https://github.com/dask/dask/pull/4805, which ensures that the warnings doesn't leak through to the user. The remaining task here is to make our signature match.


Discussion:

Resolving patch:
diff --git a/dask/array/routines.py b/dask/array/routines.py
--- a/dask/array/routines.py
+++ b/dask/array/routines.py
@@ -1266,20 +1266,19 @@ def _unravel_index_kernel(indices, func_kwargs):
 
 
 @derived_from(np)
-def unravel_index(indices, dims, order="C"):
-    # TODO: deprecate dims as well?
-    if dims and indices.size:
+def unravel_index(indices, shape, order="C"):
+    if shape and indices.size:
         unraveled_indices = tuple(
             indices.map_blocks(
                 _unravel_index_kernel,
                 dtype=np.intp,
-                chunks=(((len(dims),),) + indices.chunks),
+                chunks=(((len(shape),),) + indices.chunks),
                 new_axis=0,
-                func_kwargs={_unravel_index_keyword: dims, "order": order},
+                func_kwargs={_unravel_index_keyword: shape, "order": order},
             )
         )
     else:
-        unraveled_indices = tuple(empty((0,), dtype=np.intp, chunks=1) for i in dims)
+        unraveled_indices = tuple(empty((0,), dtype=np.intp, chunks=1) for i in shape)
 
     return unraveled_indices
 


Test patch:
Repository: dask/dask

Issue:
Array reduction name is not graph-key name
v2.15.0

I expected the graph-key name to be "my_name" instead of "sum".

```python
import dask.array as da
import numpy as np

dtype = np.int
da.reduction(
    da.ones(10, dtype, chunks=2),
    np.sum,
    np.sum,
    dtype=dtype,
    name="my_name").dask.layers.keys()
```
```python
dict_keys([
    'my_name-aggregate-271c2f44ef1b9e606cc14df3fd0c2a49',
    'my_name-partial-3e2ec900080765eb69c9589a1142cee1',
    'sum-a8e3a00efd53c7d17414ec7669d94c3d',
    'ones-6efb89dd626d392f89f98d296d7eecba'
])
```


Discussion:
Thanks for raising an issue @nre! I also would have expected that key to be `my_name-sum-...`. From a quick glance at the reduction code, it seems that `name` is not being provided to this `blockwise` call

https://github.com/dask/dask/blob/2d14075004fbca3ad7e5907f5f58ab8b05cdbdc2/dask/array/reductions.py#L155-L157

Is this something you're interested in working on? (no obligation though)

Resolving patch:
diff --git a/dask/array/reductions.py b/dask/array/reductions.py
--- a/dask/array/reductions.py
+++ b/dask/array/reductions.py
@@ -153,7 +153,7 @@ def reduction(
     inds = tuple(range(x.ndim))
     # The dtype of `tmp` doesn't actually matter, and may be incorrect.
     tmp = blockwise(
-        chunk, inds, x, inds, axis=axis, keepdims=True, dtype=dtype or float
+        chunk, inds, x, inds, axis=axis, keepdims=True, token=name, dtype=dtype or float
     )
     tmp._chunks = tuple(
         (output_size,) * len(c) if i in axis else c for i, c in enumerate(tmp.chunks)


Test patch:
diff --git a/dask/array/tests/test_reductions.py b/dask/array/tests/test_reductions.py
--- a/dask/array/tests/test_reductions.py
+++ b/dask/array/tests/test_reductions.py
@@ -1,3 +1,4 @@
+from itertools import zip_longest
 import os
 import warnings
 
@@ -513,6 +514,16 @@ def test_reduction_names():
     assert x.mean().name.startswith("mean")
 
 
+def test_general_reduction_names():
+    dtype = np.int
+    a = da.reduction(
+        da.ones(10, dtype, chunks=2), np.sum, np.sum, dtype=dtype, name="foo"
+    )
+    names, tokens = list(zip_longest(*[key[0].rsplit("-", 1) for key in a.dask]))
+    assert set(names) == {"ones", "foo", "foo-partial", "foo-aggregate"}
+    assert all(tokens)
+
+
 @pytest.mark.filterwarnings("ignore:`argmax` is not implemented by dask")
 @pytest.mark.parametrize("func", [np.sum, np.argmax])
 def test_array_reduction_out(func):
Repository: dask/dask

Issue:
apply_gufunc returns list instead of tuple
`apply_gufunc` should return a tuple if there are multiple outputs, [see docs](https://docs.dask.org/en/latest/array-api.html#dask.array.gufunc.apply_gufunc). But it returns a list instead.

```python
import dask.array as da
import numpy as np
def stats(x):
    return np.mean(x, axis=-1), np.std(x, axis=-1)
a = da.random.normal(size=(10,20,30), chunks=(5, 10, 30))
out = da.apply_gufunc(stats, "()->(),()", a)
print("is list:", isinstance(out, list))
print("is tuple:", isinstance(out, tuple))
```
Returns:
is list: True
is tuple: False

Should return:
is list: False
is tuple: True

Reason for this is, that the outputs (`leaf_arrs`) are handled as `list` inside `apply_gufunc`, and a conversion to tuple is missing before returning.

https://github.com/dask/dask/blob/3573b2ddca81aeb41a7def6dd4194020f853ab18/dask/array/gufunc.py#L459-L494

Solution:
wrap output list in `tuple()`


Discussion:

Resolving patch:
diff --git a/dask/array/gufunc.py b/dask/array/gufunc.py
--- a/dask/array/gufunc.py
+++ b/dask/array/gufunc.py
@@ -491,7 +491,7 @@ def apply_gufunc(func, signature, *args, **kwargs):
         leaf_arr = leaf_arr.transpose(tidcs)
         leaf_arrs.append(leaf_arr)
 
-    return leaf_arrs if nout else leaf_arrs[0]  # Undo *) from above
+    return (*leaf_arrs,) if nout else leaf_arrs[0]  # Undo *) from above
 
 
 class gufunc(object):


Test patch:
diff --git a/dask/array/tests/test_gufunc.py b/dask/array/tests/test_gufunc.py
--- a/dask/array/tests/test_gufunc.py
+++ b/dask/array/tests/test_gufunc.py
@@ -115,7 +115,9 @@ def stats(x):
         return np.mean(x, axis=-1), np.std(x, axis=-1)
 
     a = da.random.normal(size=(10, 20, 30), chunks=(5, 5, 30))
-    mean, std = apply_gufunc(stats, "(i)->(),()", a, output_dtypes=2 * (a.dtype,))
+    result = apply_gufunc(stats, "(i)->(),()", a, output_dtypes=2 * (a.dtype,))
+    mean, std = result
+    assert isinstance(result, tuple)
     assert mean.compute().shape == (10, 20)
     assert std.compute().shape == (10, 20)