Repository: dask/dask

Issue:
Xarray handling regression in 1.1.2
Since dask 1.1.2, this crashes:

```python
import xarray as xr                                                                             
import dask.array as da                                                                         
da.mean(xr.DataArray([1, 2, 3.0])).compute()
```
The error raised:
`TypeError: nansum() got an unexpected keyword argument 'keepdims'`

I looks like a regression to me, but maybe I'm missing something ?

Works fine in 1.1.1

Relevant packages:
dask 1.1.2
xarray 0.11.3
numpy 1.16.2


Discussion:
Reproduced.  Thank you for the excellent bug report @mraspaud 

So, I think that what happened here is that previously we were coercing things into NumPy arrays and then calling np.sum, and now we're just calling np.sum directly the input.  This is part of a larger effort to make Dask work well with other Numpy-like libraries like cupy and sparse rather than baking in Numpy explicitly.

So I think that there are a couple possible solutions here long term

1.  Xarray's nansum method could support the `keepdims` keyword argument (even if it maybe makes less sense for Xarray than for other projects)
2.  Dask to become more careful about sending down keyword arguments to constituent arrays in case they don't support them.  (or should Numpy do this?)

This is related to NEP-18.  CC'ing @hameerabbasi @shoyer @pentschev and @mhvk
For what it's worth I've fixed the relevant "bug" in satpy that was passing an xarray DataArray to a dask function (see https://github.com/pytroll/satpy/pull/633). We try to stay away from doing this as a convention, but sometimes it happens.
Tricky. I guess if one is essentially wrapping a numpy function, and if an argument really makes no sense for a given project internally, it may make most sense to also have a `**kwargs` that is passed on. But that is quite ugly.
It would be nice for Dask would recognize xarray.DataArray objects and pull out their `.data` attribute rather than the original object. I don't think there are any good use cases for putting xarray.DataArray objects inside dask arrays directly. 

Ideally this could be done via some sort of protocol, so dask doesn't need to know about xarray in particular, e.g., a `__duck_array__` method which is checked by `np.duckarray()`. This is discussed in NEP 22 but we didn't settle on a design (or name, which is possibly the hardest part): http://www.numpy.org/neps/nep-0022-ndarray-duck-typing-overview.html#principle-3-focus-on-protocols
> It would be nice for Dask would recognize xarray.DataArray objects and pull out their `.data` attribute rather than the original object. I don't think there are any good use cases for putting xarray.DataArray objects inside dask arrays directly.

We probably can't do an explicit type check for xarray data arrays everywhere.  This seems like inverting the dependency relationship a bit. 

Currently I'm somewhat inclined to say that people just shouldn't call `da.mean` on non-numpy-like objects.  Probably people should be encouraged to use `np.mean` instead and then have that rely on Xarray's `__apply_ufunc__` or `__array_function__` protocols.
I agree with @mrocklin here... We should move towards `__array_function__`.

Resolving patch:
diff --git a/dask/array/core.py b/dask/array/core.py
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -3087,6 +3087,8 @@ def asanyarray(a):
         return a
     elif hasattr(a, 'to_dask_array'):
         return a.to_dask_array()
+    elif hasattr(a, 'data') and type(a).__module__.startswith('xarray.'):
+        return asanyarray(a.data)
     elif isinstance(a, (list, tuple)) and any(isinstance(i, Array) for i in a):
         a = stack(a)
     elif not isinstance(getattr(a, 'shape', None), Iterable):


Test patch:
diff --git a/dask/array/tests/test_xarray.py b/dask/array/tests/test_xarray.py
new file mode 100644
--- /dev/null
+++ b/dask/array/tests/test_xarray.py
@@ -0,0 +1,12 @@
+import pytest
+
+import dask.array as da
+from ..utils import assert_eq
+
+xr = pytest.importorskip('xarray')
+
+
+def test_xarray():
+    y = da.mean(xr.DataArray([1, 2, 3.0]))
+
+    assert_eq(y, y)