Skip to content

Commit e611c97

Browse files
authored
Remove np.asarray in formatting.py (#8100)
1 parent ae41d82 commit e611c97

File tree

3 files changed

+65
-30
lines changed

3 files changed

+65
-30
lines changed

xarray/core/formatting.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
import pandas as pd
1717
from pandas.errors import OutOfBoundsDatetime
1818

19-
from xarray.core.duck_array_ops import array_equiv
20-
from xarray.core.indexing import ExplicitlyIndexed, MemoryCachedArray
19+
from xarray.core.duck_array_ops import array_equiv, astype
20+
from xarray.core.indexing import MemoryCachedArray
2121
from xarray.core.options import OPTIONS, _get_boolean_with_default
22-
from xarray.core.pycompat import array_type
22+
from xarray.core.pycompat import array_type, to_duck_array, to_numpy
2323
from xarray.core.utils import is_duck_array
2424

2525
if TYPE_CHECKING:
@@ -68,6 +68,8 @@ def first_n_items(array, n_desired):
6868
# might not be a numpy.ndarray. Moreover, access to elements of the array
6969
# could be very expensive (e.g. if it's only available over DAP), so go out
7070
# of our way to get them in a single call to __getitem__ using only slices.
71+
from xarray.core.variable import Variable
72+
7173
if n_desired < 1:
7274
raise ValueError("must request at least one item")
7375

@@ -78,7 +80,14 @@ def first_n_items(array, n_desired):
7880
if n_desired < array.size:
7981
indexer = _get_indexer_at_least_n_items(array.shape, n_desired, from_end=False)
8082
array = array[indexer]
81-
return np.asarray(array).flat[:n_desired]
83+
84+
# We pass variable objects in to handle indexing
85+
# with indexer above. It would not work with our
86+
# lazy indexing classes at the moment, so we cannot
87+
# pass Variable._data
88+
if isinstance(array, Variable):
89+
array = array._data
90+
return np.ravel(to_duck_array(array))[:n_desired]
8291

8392

8493
def last_n_items(array, n_desired):
@@ -87,13 +96,22 @@ def last_n_items(array, n_desired):
8796
# might not be a numpy.ndarray. Moreover, access to elements of the array
8897
# could be very expensive (e.g. if it's only available over DAP), so go out
8998
# of our way to get them in a single call to __getitem__ using only slices.
99+
from xarray.core.variable import Variable
100+
90101
if (n_desired == 0) or (array.size == 0):
91102
return []
92103

93104
if n_desired < array.size:
94105
indexer = _get_indexer_at_least_n_items(array.shape, n_desired, from_end=True)
95106
array = array[indexer]
96-
return np.asarray(array).flat[-n_desired:]
107+
108+
# We pass variable objects in to handle indexing
109+
# with indexer above. It would not work with our
110+
# lazy indexing classes at the moment, so we cannot
111+
# pass Variable._data
112+
if isinstance(array, Variable):
113+
array = array._data
114+
return np.ravel(to_duck_array(array))[-n_desired:]
97115

98116

99117
def last_item(array):
@@ -103,7 +121,8 @@ def last_item(array):
103121
return []
104122

105123
indexer = (slice(-1, None),) * array.ndim
106-
return np.ravel(np.asarray(array[indexer])).tolist()
124+
# to_numpy since dask doesn't support tolist
125+
return np.ravel(to_numpy(array[indexer])).tolist()
107126

108127

109128
def calc_max_rows_first(max_rows: int) -> int:
@@ -171,10 +190,10 @@ def format_item(x, timedelta_format=None, quote_strings=True):
171190

172191
def format_items(x):
173192
"""Returns a succinct summaries of all items in a sequence as strings"""
174-
x = np.asarray(x)
193+
x = to_duck_array(x)
175194
timedelta_format = "datetime"
176195
if np.issubdtype(x.dtype, np.timedelta64):
177-
x = np.asarray(x, dtype="timedelta64[ns]")
196+
x = astype(x, dtype="timedelta64[ns]")
178197
day_part = x[~pd.isnull(x)].astype("timedelta64[D]").astype("timedelta64[ns]")
179198
time_needed = x[~pd.isnull(x)] != day_part
180199
day_needed = day_part != np.timedelta64(0, "ns")
@@ -584,12 +603,9 @@ def limit_lines(string: str, *, limit: int):
584603
def short_array_repr(array):
585604
from xarray.core.common import AbstractArray
586605

587-
if isinstance(array, ExplicitlyIndexed):
588-
array = array.get_duck_array()
589-
elif isinstance(array, AbstractArray):
606+
if isinstance(array, AbstractArray):
590607
array = array.data
591-
if not is_duck_array(array):
592-
array = np.asarray(array)
608+
array = to_duck_array(array)
593609

594610
# default to lower precision so a full (abbreviated) line can fit on
595611
# one line with the default display_width

xarray/core/pycompat.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,37 @@ def is_chunked_array(x) -> bool:
101101

102102
def is_0d_dask_array(x):
103103
return is_duck_dask_array(x) and is_scalar(x)
104+
105+
106+
def to_numpy(data) -> np.ndarray:
107+
from xarray.core.indexing import ExplicitlyIndexed
108+
from xarray.core.parallelcompat import get_chunked_array_type
109+
110+
if isinstance(data, ExplicitlyIndexed):
111+
data = data.get_duck_array()
112+
113+
# TODO first attempt to call .to_numpy() once some libraries implement it
114+
if hasattr(data, "chunks"):
115+
chunkmanager = get_chunked_array_type(data)
116+
data, *_ = chunkmanager.compute(data)
117+
if isinstance(data, array_type("cupy")):
118+
data = data.get()
119+
# pint has to be imported dynamically as pint imports xarray
120+
if isinstance(data, array_type("pint")):
121+
data = data.magnitude
122+
if isinstance(data, array_type("sparse")):
123+
data = data.todense()
124+
data = np.asarray(data)
125+
126+
return data
127+
128+
129+
def to_duck_array(data):
130+
from xarray.core.indexing import ExplicitlyIndexed
131+
132+
if isinstance(data, ExplicitlyIndexed):
133+
return data.get_duck_array()
134+
elif is_duck_array(data):
135+
return data
136+
else:
137+
return np.asarray(data)

xarray/core/variable.py

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828
from xarray.core.options import OPTIONS, _get_keep_attrs
2929
from xarray.core.parallelcompat import get_chunked_array_type, guess_chunkmanager
3030
from xarray.core.pycompat import (
31-
array_type,
3231
integer_types,
3332
is_0d_dask_array,
3433
is_chunked_array,
3534
is_duck_dask_array,
35+
to_numpy,
3636
)
3737
from xarray.core.utils import (
3838
OrderedSet,
@@ -1093,22 +1093,7 @@ def chunk(
10931093
def to_numpy(self) -> np.ndarray:
10941094
"""Coerces wrapped data to numpy and returns a numpy.ndarray"""
10951095
# TODO an entrypoint so array libraries can choose coercion method?
1096-
data = self.data
1097-
1098-
# TODO first attempt to call .to_numpy() once some libraries implement it
1099-
if hasattr(data, "chunks"):
1100-
chunkmanager = get_chunked_array_type(data)
1101-
data, *_ = chunkmanager.compute(data)
1102-
if isinstance(data, array_type("cupy")):
1103-
data = data.get()
1104-
# pint has to be imported dynamically as pint imports xarray
1105-
if isinstance(data, array_type("pint")):
1106-
data = data.magnitude
1107-
if isinstance(data, array_type("sparse")):
1108-
data = data.todense()
1109-
data = np.asarray(data)
1110-
1111-
return data
1096+
return to_numpy(self._data)
11121097

11131098
def as_numpy(self) -> Self:
11141099
"""Coerces wrapped data into a numpy array, returning a Variable."""

0 commit comments

Comments
 (0)