Skip to content

Commit 223a05f

Browse files
authored
Ensure explicitly indexed arrays are preserved (#3027)
* Ensure indexing explicitly indexed arrays don't leak out. Previously, indexing an ImplicitToExplicitIndexingAdapter object could directly return an ExplicitlyIndexed object, which could not be indexed normally. This resulted in broken behavior with dask's new `_meta` attribute. This change almost but not entirely fixes xarray on dask master. There are still errors raised inside two tests from dask's `blockwise_meta` helper function: > return meta.astype(dtype) E AttributeError: 'ImplicitToExplicitIndexingAdapter' object has no attribute 'astype' * Set meta in dask.array.from_array
1 parent 56fc325 commit 223a05f

File tree

4 files changed

+29
-4
lines changed

4 files changed

+29
-4
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ matrix:
1616
- env:
1717
- CONDA_ENV=py36
1818
- EXTRA_FLAGS="--run-flaky --run-network-tests"
19+
- env: CONDA_ENV=py36-dask-dev
1920
- env: CONDA_ENV=py36-pandas-dev
2021
- env: CONDA_ENV=py36-rasterio
2122
- env: CONDA_ENV=py36-zarr-dev
22-
- env: CONDA_ENV=py36-dask-dev
2323
- env: CONDA_ENV=docs
2424
- env: CONDA_ENV=lint
2525
- env: CONDA_ENV=typing

xarray/core/indexing.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,13 @@ def __array__(self, dtype=None):
453453

454454
def __getitem__(self, key):
455455
key = expanded_indexer(key, self.ndim)
456-
return self.array[self.indexer_cls(key)]
456+
result = self.array[self.indexer_cls(key)]
457+
if isinstance(result, ExplicitlyIndexed):
458+
return type(self)(result, self.indexer_cls)
459+
else:
460+
# Sometimes explicitly indexed arrays return NumPy arrays or
461+
# scalars.
462+
return result
457463

458464

459465
class LazilyOuterIndexedArray(ExplicitlyIndexedNDArrayMixin):

xarray/core/variable.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import typing
44
from collections import OrderedDict, defaultdict
55
from datetime import timedelta
6+
from distutils.version import LooseVersion
67

78
import numpy as np
89
import pandas as pd
@@ -870,6 +871,7 @@ def chunk(self, chunks=None, name=None, lock=False):
870871
-------
871872
chunked : xarray.Variable
872873
"""
874+
import dask
873875
import dask.array as da
874876

875877
if utils.is_dict_like(chunks):
@@ -892,7 +894,17 @@ def chunk(self, chunks=None, name=None, lock=False):
892894
# https://github.com/dask/dask/issues/2883
893895
data = indexing.ImplicitToExplicitIndexingAdapter(
894896
data, indexing.OuterIndexer)
895-
data = da.from_array(data, chunks, name=name, lock=lock)
897+
898+
# For now, assume that all arrays that we wrap with dask (including
899+
# our lazily loaded backend array classes) should use NumPy array
900+
# operations.
901+
if LooseVersion(dask.__version__) > '1.2.2':
902+
kwargs = dict(meta=np.ndarray)
903+
else:
904+
kwargs = dict()
905+
906+
data = da.from_array(
907+
data, chunks, name=name, lock=lock, **kwargs)
896908

897909
return type(self)(self.dims, data, self._attrs, self._encoding,
898910
fastpath=True)

xarray/tests/test_indexing.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,13 +505,20 @@ def test_decompose_indexers(shape, indexer_mode, indexing_support):
505505

506506

507507
def test_implicit_indexing_adapter():
508-
array = np.arange(10)
508+
array = np.arange(10, dtype=np.int64)
509509
implicit = indexing.ImplicitToExplicitIndexingAdapter(
510510
indexing.NumpyIndexingAdapter(array), indexing.BasicIndexer)
511511
np.testing.assert_array_equal(array, np.asarray(implicit))
512512
np.testing.assert_array_equal(array, implicit[:])
513513

514514

515+
def test_implicit_indexing_adapter_copy_on_write():
516+
array = np.arange(10, dtype=np.int64)
517+
implicit = indexing.ImplicitToExplicitIndexingAdapter(
518+
indexing.CopyOnWriteArray(array))
519+
assert isinstance(implicit[:], indexing.ImplicitToExplicitIndexingAdapter)
520+
521+
515522
def test_outer_indexer_consistency_with_broadcast_indexes_vectorized():
516523
def nonzero(x):
517524
if isinstance(x, np.ndarray) and x.dtype.kind == 'b':

0 commit comments

Comments
 (0)