Repository: pydata/xarray

Issue:
Changed behavior for replacing coordinates on dataset.
#### MCVE Code Sample
We noticed a change in behavior in xarray that broke a test in [xgcm](https://github.com/xgcm/xgcm/pull/130#issuecomment-538834037).

Consider this code example:
```python
import xarray as xr
import numpy as np
x = np.arange(5)
data = xr.DataArray(np.random.rand(5), coords={'x':x
}, dims=['x'])
x_c = np.arange(5) + 0.5
data_c = xr.DataArray(np.random.rand(5), coords={'x_c':x_c
}, dims=['x_c'])
ds = xr.Dataset({'data':data, 'data_c':data_c})
del ds['data_c']

ds['x_c'] = ds['x_c'][:3]
ds
```


#### Expected Output
In previous versions of xarray this resulted in 
```
<xarray.Dataset>
Dimensions:  (x: 5, x_c: 3)
Coordinates:
  * x_c      (x_c) float64 0.5 1.5 2.5
  * x        (x) int64 0 1 2 3 4
Data variables:
    data     (x) float64 0.3828 0.6016 0.3603 0.414 0.35
```
 (I tested right now with an older `v0.11.3` but this works with `v0.13` as well.

In the current master branch instead the coordinate gets padded with nans:
```
<xarray.Dataset>
Dimensions:  (x: 5, x_c: 5)
Coordinates:
  * x_c      (x_c) float64 0.5 1.5 2.5 nan nan
  * x        (x) int64 0 1 2 3 4
Data variables:
    data     (x) float64 0.8369 0.4197 0.3058 0.7419 0.8126
```


#### Problem Description
We fixed the test in a new PR, but @dcherian encouraged me to submit this.


#### Output of ``xr.show_versions()``
<details>
INSTALLED VERSIONS
------------------
commit: None
python: 3.7.4 (default, Aug 13 2019, 15:17:50) 
[Clang 4.0.1 (tags/RELEASE_401/final)]
python-bits: 64
OS: Darwin
OS-release: 18.6.0
machine: x86_64
processor: i386
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8
libhdf5: None
libnetcdf: None

xarray: 0.13.0+24.g4254b4af
pandas: 0.25.1
numpy: 1.17.2
scipy: None
netCDF4: None
pydap: None
h5netcdf: None
h5py: None
Nio: None
zarr: None
cftime: None
nc_time_axis: None
PseudoNetCDF: None
rasterio: None
cfgrib: None
iris: None
bottleneck: None
dask: 2.5.0
distributed: 2.5.1
matplotlib: None
cartopy: None
seaborn: None
numbagg: None
setuptools: 41.2.0
pip: 19.2.3
conda: None
pytest: 5.2.0
IPython: 7.8.0
sphinx: None

</details>


Discussion:
jhamman: LGTM. Thanks @shoyer for the quick fix. 

Patch:
diff --git a/xarray/core/alignment.py b/xarray/core/alignment.py
index b4fee177..a905dd37 100644
--- a/xarray/core/alignment.py
+++ b/xarray/core/alignment.py
@@ -374,7 +374,13 @@ def deep_align(
         elif is_dict_like(variables):
             current_out = OrderedDict()
             for k, v in variables.items():
-                if is_alignable(v):
+                if is_alignable(v) and k not in indexes:
+                    # Skip variables in indexes for alignment, because these
+                    # should to be overwritten instead:
+                    # https://github.com/pydata/xarray/issues/725
+                    # https://github.com/pydata/xarray/issues/3377
+                    # TODO(shoyer): doing this here feels super-hacky -- can we
+                    # move it explicitly into merge instead?
                     positions.append(position)
                     keys.append(k)
                     targets.append(v)


Test patch:
diff --git a/xarray/tests/test_dataset.py b/xarray/tests/test_dataset.py
index fdd5a419..e9efd5e7 100644
--- a/xarray/tests/test_dataset.py
+++ b/xarray/tests/test_dataset.py
@@ -3047,6 +3047,21 @@ class TestDataset:
         expected = Dataset({"x": ("y", [4, 5, 6])}, {"y": range(3)})
         assert_identical(ds, expected)
 
+    def test_setitem_dimension_override(self):
+        # regression test for GH-3377
+        ds = xr.Dataset({"x": [0, 1, 2]})
+        ds["x"] = ds["x"][:2]
+        expected = Dataset({"x": [0, 1]})
+        assert_identical(ds, expected)
+
+        ds = xr.Dataset({"x": [0, 1, 2]})
+        ds["x"] = np.array([0, 1])
+        assert_identical(ds, expected)
+
+        ds = xr.Dataset({"x": [0, 1, 2]})
+        ds.coords["x"] = [0, 1]
+        assert_identical(ds, expected)
+
     def test_setitem_with_coords(self):
         # Regression test for GH:2068
         ds = create_test_data()