Repository: dask/dask

Issue:
Dask array setitem with differently chunked data provides wrong shape
```python
>>> import dask.array as da
>>> x = da.zeros(5, chunks=2)
>>> m = da.zeros(5, chunks=3)
>>> x[m>0] = 1
>>> print x.shape, x.compute().shape
(5,) (4,)
```

This should probably unifiy chunks before slicing

Discussion:

Patch:
diff --git a/.gitignore b/.gitignore
index 7fc3d3c76..f1f69b4c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.hypothesis
 *.py[cod]
 __pycache__/
 *.egg-info
diff --git a/dask/array/core.py b/dask/array/core.py
index 384bc1fdc..a8e11b807 100644
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -1337,6 +1337,7 @@ class Array(DaskMethodsMixin):
             self.dtype = y.dtype
             self.dask = y.dask
             self.name = y.name
+            self._chunks = y.chunks
             return self
         else:
             raise NotImplementedError("Item assignment with %s not supported"
diff --git a/dask/array/random.py b/dask/array/random.py
index 5d5a6bb0b..8f299e7d0 100644
--- a/dask/array/random.py
+++ b/dask/array/random.py
@@ -217,6 +217,11 @@ class RandomState(object):
                 size = (size,)
 
             chunks = normalize_chunks(chunks, size, dtype=np.float64)
+            if not replace and len(chunks[0]) > 1:
+                    err_msg = ('replace=False is not currently supported for '
+                               'dask.array.choice with multi-chunk output '
+                               'arrays')
+                    raise NotImplementedError(err_msg)
             sizes = list(product(*chunks))
             state_data = random_state_data(len(sizes), self._numpy_state)
 
diff --git a/docs/README.rst b/docs/README.rst
index bb5afdb9d..932b24eb2 100644
--- a/docs/README.rst
+++ b/docs/README.rst
@@ -5,6 +5,6 @@ these commands suffice::
   git clone git@github.com:dask/dask.git
   cd dask/docs
   conda create -n daskdocs --file requirements-docs.txt
-  source activate daskdocs
+  conda activate daskdocs
   make html
   open build/html/index.html
diff --git a/docs/source/array-api.rst b/docs/source/array-api.rst
index 4abb29387..73e4da786 100644
--- a/docs/source/array-api.rst
+++ b/docs/source/array-api.rst
@@ -338,7 +338,7 @@ Create and Store Arrays
 Generalized Ufuncs
 ~~~~~~~~~~~~~~~~~~
 
-.. currentmodule:: dask.array
+.. currentmodule:: dask.array.gufunc
 
 .. autosummary::
    apply_gufunc


Test patch:
diff --git a/dask/array/tests/test_random.py b/dask/array/tests/test_random.py
index 4624abf8e..5d270419c 100644
--- a/dask/array/tests/test_random.py
+++ b/dask/array/tests/test_random.py
@@ -268,6 +268,14 @@ def test_choice():
         with pytest.raises(ValueError):
             da.random.choice(a, size=size, chunks=chunks, p=p)
 
+    with pytest.raises(NotImplementedError):
+        da.random.choice(da_a, size=size, chunks=chunks, replace=False)
+
+    # Want to make sure replace=False works for a single-partition output array
+    x = da.random.choice(da_a, size=da_a.shape[0], chunks=-1, replace=False)
+    res = x.compute()
+    assert len(res) == len(np.unique(res))
+
 
 def test_create_with_auto_dimensions():
     with dask.config.set({'array.chunk-size': '128MiB'}):
diff --git a/dask/array/tests/test_slicing.py b/dask/array/tests/test_slicing.py
index 6ed1a3606..5fc3c79d2 100644
--- a/dask/array/tests/test_slicing.py
+++ b/dask/array/tests/test_slicing.py
@@ -798,3 +798,19 @@ def test_pathological_unsorted_slicing():
 
     assert '10' in str(info.list[0])
     assert 'out-of-order' in str(info.list[0])
+
+
+@pytest.mark.parametrize('params', [(2, 2, 1), (5, 3, 2)])
+def test_setitem_with_different_chunks_preserves_shape(params):
+    """ Reproducer for https://github.com/dask/dask/issues/3730.
+
+    Mutating based on an array with different chunks can cause new chunks to be
+    used.  We need to ensure those new chunk sizes are applied to the mutated
+    array, otherwise the array won't generate the correct keys.
+    """
+    array_size, chunk_size1, chunk_size2 = params
+    x = da.zeros(array_size, chunks=chunk_size1)
+    mask = da.zeros(array_size, chunks=chunk_size2)
+    x[mask] = 1
+    result = x.compute()
+    assert x.shape == result.shape
diff --git a/dask/dataframe/io/tests/test_hdf.py b/dask/dataframe/io/tests/test_hdf.py
index 7a316a6ce..9252ee399 100644
--- a/dask/dataframe/io/tests/test_hdf.py
+++ b/dask/dataframe/io/tests/test_hdf.py
@@ -535,6 +535,7 @@ def test_read_hdf_doesnt_segfault():
 
 
 def test_hdf_filenames():
+    pytest.importorskip('tables')
     df = pd.DataFrame({'x': ['a', 'b', 'c', 'd'],
                        'y': [1, 2, 3, 4]}, index=[1., 2., 3., 4.])
     ddf = dd.from_pandas(df, npartitions=2)