Skip to content

Commit c4497ff

Browse files
DavidMertzshoyer
authored andcommitted
Better docs and errors about expand_dims() view (#3114)
* 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
1 parent 4cbe635 commit c4497ff

File tree

5 files changed

+27
-3
lines changed

5 files changed

+27
-3
lines changed

doc/whats-new.rst

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ Enhancements
3030
Bug fixes
3131
~~~~~~~~~
3232

33+
- Improved error handling and documentation for `.expand_dims()`
34+
read-only view.
35+
3336
.. _whats-new.0.12.3:
3437

3538
v0.12.3 (10 July 2019)

xarray/core/dataarray.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,9 @@ def expand_dims(self, dim: Union[None, Hashable, Sequence[Hashable],
12711271
Mapping[Hashable, Any]] = None,
12721272
axis=None, **dim_kwargs: Any) -> 'DataArray':
12731273
"""Return a new object with an additional axis (or axes) inserted at
1274-
the corresponding position in the array shape.
1274+
the corresponding position in the array shape. The new object is a
1275+
view into the underlying array, not a copy.
1276+
12751277
12761278
If dim is already a scalar coordinate, it will be promoted to a 1D
12771279
coordinate consisting of a single value.

xarray/core/dataset.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2505,7 +2505,8 @@ def swap_dims(self, dims_dict, inplace=None):
25052505

25062506
def expand_dims(self, dim=None, axis=None, **dim_kwargs):
25072507
"""Return a new object with an additional axis (or axes) inserted at
2508-
the corresponding position in the array shape.
2508+
the corresponding position in the array shape. The new object is a
2509+
view into the underlying array, not a copy.
25092510
25102511
If dim is already a scalar coordinate, it will be promoted to a 1D
25112512
coordinate consisting of a single value.

xarray/core/indexing.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1177,7 +1177,15 @@ def __getitem__(self, key):
11771177

11781178
def __setitem__(self, key, value):
11791179
array, key = self._indexing_array_and_key(key)
1180-
array[key] = value
1180+
try:
1181+
array[key] = value
1182+
except ValueError:
1183+
# More informative exception if read-only view
1184+
if not array.flags.writeable and not array.flags.owndata:
1185+
raise ValueError("Assignment destination is a view. "
1186+
"Do you want to .copy() array first?")
1187+
else:
1188+
raise
11811189

11821190

11831191
class DaskIndexingAdapter(ExplicitlyIndexedNDArrayMixin):

xarray/tests/test_indexing.py

+10
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,16 @@ def test_indexer(data, x, expected_pos, expected_idx=None):
144144
[True, True, True, True, False, False, False, False],
145145
pd.MultiIndex.from_product([[1, 2], [-1, -2]]))
146146

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

148158
class TestLazyArray:
149159
def test_slice_slice(self):

0 commit comments

Comments
 (0)