Skip to content

Commit

Permalink
Better docs and errors about expand_dims() view (#3114)
Browse files Browse the repository at this point in the history
* Better docs and errors about expand_dims() view

* Add test and whatsnew note

* Remove trailing whitespace

* Whitespace for PEP8

* Py35 compatible test

* Better docs and errors about expand_dims() view

* Add test and whatsnew note

* Remove trailing whitespace

* Whitespace for PEP8

* Py35 compatible test

* Improved exception testing
  • Loading branch information
DavidMertz authored and shoyer committed Jul 14, 2019
1 parent 4cbe635 commit c4497ff
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 3 deletions.
3 changes: 3 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Enhancements
Bug fixes
~~~~~~~~~

- Improved error handling and documentation for `.expand_dims()`
read-only view.

.. _whats-new.0.12.3:

v0.12.3 (10 July 2019)
Expand Down
4 changes: 3 additions & 1 deletion xarray/core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,9 @@ def expand_dims(self, dim: Union[None, Hashable, Sequence[Hashable],
Mapping[Hashable, Any]] = None,
axis=None, **dim_kwargs: Any) -> 'DataArray':
"""Return a new object with an additional axis (or axes) inserted at
the corresponding position in the array shape.
the corresponding position in the array shape. The new object is a
view into the underlying array, not a copy.
If dim is already a scalar coordinate, it will be promoted to a 1D
coordinate consisting of a single value.
Expand Down
3 changes: 2 additions & 1 deletion xarray/core/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2505,7 +2505,8 @@ def swap_dims(self, dims_dict, inplace=None):

def expand_dims(self, dim=None, axis=None, **dim_kwargs):
"""Return a new object with an additional axis (or axes) inserted at
the corresponding position in the array shape.
the corresponding position in the array shape. The new object is a
view into the underlying array, not a copy.
If dim is already a scalar coordinate, it will be promoted to a 1D
coordinate consisting of a single value.
Expand Down
10 changes: 9 additions & 1 deletion xarray/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,15 @@ def __getitem__(self, key):

def __setitem__(self, key, value):
array, key = self._indexing_array_and_key(key)
array[key] = value
try:
array[key] = value
except ValueError:
# More informative exception if read-only view
if not array.flags.writeable and not array.flags.owndata:
raise ValueError("Assignment destination is a view. "
"Do you want to .copy() array first?")
else:
raise


class DaskIndexingAdapter(ExplicitlyIndexedNDArrayMixin):
Expand Down
10 changes: 10 additions & 0 deletions xarray/tests/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ def test_indexer(data, x, expected_pos, expected_idx=None):
[True, True, True, True, False, False, False, False],
pd.MultiIndex.from_product([[1, 2], [-1, -2]]))

def test_read_only_view(self):
from collections import OrderedDict
arr = DataArray(np.random.rand(3, 3),
coords={'x': np.arange(3), 'y': np.arange(3)},
dims=('x', 'y')) # Create a 2D DataArray
arr = arr.expand_dims(OrderedDict([('z', 3)]), -1) # New dimension 'z'
arr['z'] = np.arange(3) # New coords to dimension 'z'
with pytest.raises(ValueError, match='Do you want to .copy()'):
arr.loc[0, 0, 0] = 999


class TestLazyArray:
def test_slice_slice(self):
Expand Down

0 comments on commit c4497ff

Please sign in to comment.