Repository: dask/dask

Issue:
Add meta to the repr for dask arrays?
It seems like `meta` would be nice to know for debugging. It's already in the HTML repr -- what about putting it in the text repr, too?

For example, instead of:
```
dask.array<array, shape=(3, 3), dtype=float64, chunksize=(3, 3)>
```
we could have:
```
dask.array<array, shape=(3, 3), dtype=float64, chunksize=(3, 3), meta=sparse.COO>
```

Or maybe drop the existing `name` field in favor of meta, since that isn't especially informative.

This came up in https://github.com/pydata/xarray/pull/3211, cc @crusaderky 


Discussion:
Seems fine to me.

On Fri, Aug 16, 2019 at 3:19 PM Stephan Hoyer <notifications@github.com>
wrote:

> It seems like meta would be nice to know for debugging. It's already in
> the HTML repr -- what about putting it in the text repr, too?
>
> For example, instead of:
>
> dask.array<array, shape=(3, 3), dtype=float64, chunksize=(3, 3)>
>
> we could have:
>
> dask.array<array, shape=(3, 3), dtype=float64, chunksize=(3, 3), meta=sparse.COO>
>
> Or maybe drop the existing name field in favor of meta, since that isn't
> especially informative.
>
> This came up in pydata/xarray#3211
> <https://github.com/pydata/xarray/pull/3211>, cc @crusaderky
> <https://github.com/crusaderky>
>
> —
> 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/5288?email_source=notifications&email_token=AACKZTFIN3KDG6ITA6FFBELQE34T7A5CNFSM4IMMDSTKYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HFW5KEQ>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AACKZTFX2C7VTOIBWZBTGWLQE34T7ANCNFSM4IMMDSTA>
> .
>

+1 adding `meta` to the text repr seems like a good idea to me

Resolving patch:
diff --git a/dask/array/core.py b/dask/array/core.py
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -492,7 +492,7 @@ def map_blocks(
     ...     return np.array([a.max(), b.max()])
 
     >>> da.map_blocks(func, x, y, chunks=(2,), dtype='i8')
-    dask.array<func, shape=(20,), dtype=int64, chunksize=(2,)>
+    dask.array<func, shape=(20,), dtype=int64, chunksize=(2,), chunktype=numpy.ndarray>
 
     >>> _.compute()
     array([ 99,   9, 199,  19, 299,  29, 399,  39, 499,  49, 599,  59, 699,
@@ -534,7 +534,7 @@ def map_blocks(
     ...     return np.arange(loc[0], loc[1])
 
     >>> da.map_blocks(func, chunks=((4, 4),), dtype=np.float_)
-    dask.array<func, shape=(8,), dtype=float64, chunksize=(4,)>
+    dask.array<func, shape=(8,), dtype=float64, chunksize=(4,), chunktype=numpy.ndarray>
 
     >>> _.compute()
     array([0, 1, 2, 3, 4, 5, 6, 7])
@@ -543,7 +543,7 @@ def map_blocks(
     the optional ``token`` keyword argument.
 
     >>> x.map_blocks(lambda x: x + 1, name='increment')  # doctest: +SKIP
-    dask.array<increment, shape=(100,), dtype=int64, chunksize=(10,)>
+    dask.array<increment, shape=(100,), dtype=int64, chunksize=(10,), chunktype=numpy.ndarray>
     """
     if not callable(func):
         msg = (
@@ -1153,15 +1153,17 @@ def __repr__(self):
 
         >>> import dask.array as da
         >>> da.ones((10, 10), chunks=(5, 5), dtype='i4')
-        dask.array<..., shape=(10, 10), dtype=int32, chunksize=(5, 5)>
+        dask.array<..., shape=(10, 10), dtype=int32, chunksize=(5, 5), chunktype=numpy.ndarray>
         """
         chunksize = str(self.chunksize)
         name = self.name.rsplit("-", 1)[0]
-        return "dask.array<%s, shape=%s, dtype=%s, chunksize=%s>" % (
+        return "dask.array<%s, shape=%s, dtype=%s, chunksize=%s, chunktype=%s.%s>" % (
             name,
             self.shape,
             self.dtype,
             chunksize,
+            type(self._meta).__module__.split(".")[0],
+            type(self._meta).__name__,
         )
 
     def _repr_html_(self):
@@ -2890,7 +2892,7 @@ def from_delayed(value, shape, dtype=None, meta=None, name=None):
     >>> value = dask.delayed(np.ones)(5)
     >>> array = da.from_delayed(value, (5,), dtype=float)
     >>> array
-    dask.array<from-value, shape=(5,), dtype=float64, chunksize=(5,)>
+    dask.array<from-value, shape=(5,), dtype=float64, chunksize=(5,), chunktype=numpy.ndarray>
     >>> array.compute()
     array([1., 1., 1., 1., 1.])
     """
@@ -3569,11 +3571,11 @@ def asarray(a, **kwargs):
     >>> import numpy as np
     >>> x = np.arange(3)
     >>> da.asarray(x)
-    dask.array<array, shape=(3,), dtype=int64, chunksize=(3,)>
+    dask.array<array, shape=(3,), dtype=int64, chunksize=(3,), chunktype=numpy.ndarray>
 
     >>> y = [[1, 2, 3], [4, 5, 6]]
     >>> da.asarray(y)
-    dask.array<array, shape=(2, 3), dtype=int64, chunksize=(2, 3)>
+    dask.array<array, shape=(2, 3), dtype=int64, chunksize=(2, 3), chunktype=numpy.ndarray>
     """
     if isinstance(a, Array):
         return a
@@ -3607,11 +3609,11 @@ def asanyarray(a):
     >>> import numpy as np
     >>> x = np.arange(3)
     >>> da.asanyarray(x)
-    dask.array<array, shape=(3,), dtype=int64, chunksize=(3,)>
+    dask.array<array, shape=(3,), dtype=int64, chunksize=(3,), chunktype=numpy.ndarray>
 
     >>> y = [[1, 2, 3], [4, 5, 6]]
     >>> da.asanyarray(y)
-    dask.array<array, shape=(2, 3), dtype=int64, chunksize=(2, 3)>
+    dask.array<array, shape=(2, 3), dtype=int64, chunksize=(2, 3), chunktype=numpy.ndarray>
     """
     if isinstance(a, Array):
         return a
diff --git a/dask/dataframe/io/io.py b/dask/dataframe/io/io.py
--- a/dask/dataframe/io/io.py
+++ b/dask/dataframe/io/io.py
@@ -516,7 +516,7 @@ def to_records(df):
     Examples
     --------
     >>> df.to_records()  # doctest: +SKIP
-    dask.array<shape=(nan,), dtype=(numpy.record, [('ind', '<f8'), ('x', 'O'), ('y', '<i8')]), chunksize=(nan,)>
+    dask.array<to_records, shape=(nan,), dtype=(numpy.record, [('ind', '<f8'), ('x', 'O'), ('y', '<i8')]), chunksize=(nan,), chunktype=numpy.ndarray>  # noqa: E501
 
     See Also
     --------


Test patch:
diff --git a/dask/array/tests/test_array_core.py b/dask/array/tests/test_array_core.py
--- a/dask/array/tests/test_array_core.py
+++ b/dask/array/tests/test_array_core.py
@@ -1419,6 +1419,16 @@ def test_repr():
     assert len(str(d)) < 1000
 
 
+def test_repr_meta():
+    d = da.ones((4, 4), chunks=(2, 2))
+    assert "chunktype=numpy.ndarray" in repr(d)
+
+    # Test non-numpy meta
+    sparse = pytest.importorskip("sparse")
+    s = d.map_blocks(sparse.COO)
+    assert "chunktype=sparse.COO" in repr(s)
+
+
 def test_slicing_with_ellipsis():
     x = np.arange(256).reshape((4, 4, 4, 4))
     d = da.from_array(x, chunks=((2, 2, 2, 2)))