Skip to content
forked from pydata/xarray

Commit 741d84d

Browse files
committed
Merge branch 'master' into join-override
* master: enable sphinx.ext.napoleon (pydata#3180) remove type annotations from autodoc method signatures (pydata#3179) Fix regression: IndexVariable.copy(deep=True) casts dtype=U to object (pydata#3095) Fix distributed.Client.compute applied to DataArray (pydata#3173)
2 parents 8263d38 + 01a9baa commit 741d84d

File tree

8 files changed

+77
-25
lines changed

8 files changed

+77
-25
lines changed

doc/conf.py

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
'sphinx.ext.intersphinx',
6767
'sphinx.ext.extlinks',
6868
'sphinx.ext.mathjax',
69+
'sphinx.ext.napoleon',
6970
'numpydoc',
7071
'IPython.sphinxext.ipython_directive',
7172
'IPython.sphinxext.ipython_console_highlighting',
@@ -83,6 +84,10 @@
8384
}
8485

8586
autosummary_generate = True
87+
autodoc_typehints = 'none'
88+
89+
napoleon_use_param = True
90+
napoleon_use_rtype = True
8691

8792
numpydoc_class_members_toctree = True
8893
numpydoc_show_class_members = False

doc/whats-new.rst

+8-3
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,22 @@ Enhancements
4646

4747
Bug fixes
4848
~~~~~~~~~
49-
50-
- Improved error handling and documentation for `.expand_dims()`
49+
- Fix regression introduced in v0.12.2 where ``copy(deep=True)`` would convert
50+
unicode indices to dtype=object (:issue:`3094`).
51+
By `Guido Imperiale <https://github.com/crusaderky>`_.
52+
- Improved error handling and documentation for `.expand_dims()`
5153
read-only view.
5254
- Fix tests for big-endian systems (:issue:`3125`).
5355
By `Graham Inggs <https://github.com/ginggs>`_.
5456
- XFAIL several tests which are expected to fail on ARM systems
5557
due to a ``datetime`` issue in NumPy (:issue:`2334`).
5658
By `Graham Inggs <https://github.com/ginggs>`_.
5759
- Fixed bug in ``combine_by_coords()`` causing a `ValueError` if the input had
58-
an unused dimension with coordinates which were not monotonic (:issue`3150`).
60+
an unused dimension with coordinates which were not monotonic (:issue:`3150`).
5961
By `Tom Nicholas <http://github.com/TomNicholas>`_.
62+
- Fixed crash when applying ``distributed.Client.compute()`` to a DataArray
63+
(:issue:`3171`). By `Guido Imperiale <https://github.com/crusaderky>`_.
64+
6065

6166
.. _whats-new.0.12.3:
6267

xarray/core/dataarray.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ def _replace(
300300
self,
301301
variable: Variable = None,
302302
coords=None,
303-
name: Union[Hashable, None, ReprObject] = __default,
303+
name: Optional[Hashable] = __default,
304304
) -> 'DataArray':
305305
if variable is None:
306306
variable = self.variable
@@ -313,7 +313,7 @@ def _replace(
313313
def _replace_maybe_drop_dims(
314314
self,
315315
variable: Variable,
316-
name: Union[str, None, utils.ReprObject] = __default
316+
name: Optional[Hashable] = __default
317317
) -> 'DataArray':
318318
if variable.dims == self.dims and variable.shape == self.shape:
319319
coords = self._coords.copy()
@@ -356,7 +356,7 @@ def _to_temp_dataset(self) -> Dataset:
356356
def _from_temp_dataset(
357357
self,
358358
dataset: Dataset,
359-
name: Union[Hashable, ReprObject] = __default
359+
name: Hashable = __default
360360
) -> 'DataArray':
361361
variable = dataset._variables.pop(_THIS_ARRAY)
362362
coords = dataset._variables

xarray/core/indexing.py

+31-9
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
from collections import defaultdict
44
from contextlib import suppress
55
from datetime import timedelta
6-
from typing import Sequence
6+
from typing import Any, Tuple, Sequence, Union
77

88
import numpy as np
99
import pandas as pd
1010

1111
from . import duck_array_ops, nputils, utils
12+
from .npcompat import DTypeLike
1213
from .pycompat import dask_array_type, integer_types
1314
from .utils import is_dict_like
1415

@@ -1227,9 +1228,10 @@ def transpose(self, order):
12271228

12281229

12291230
class PandasIndexAdapter(ExplicitlyIndexedNDArrayMixin):
1230-
"""Wrap a pandas.Index to preserve dtypes and handle explicit indexing."""
1231+
"""Wrap a pandas.Index to preserve dtypes and handle explicit indexing.
1232+
"""
12311233

1232-
def __init__(self, array, dtype=None):
1234+
def __init__(self, array: Any, dtype: DTypeLike = None):
12331235
self.array = utils.safe_cast_to_index(array)
12341236
if dtype is None:
12351237
if isinstance(array, pd.PeriodIndex):
@@ -1241,13 +1243,15 @@ def __init__(self, array, dtype=None):
12411243
dtype = np.dtype('O')
12421244
else:
12431245
dtype = array.dtype
1246+
else:
1247+
dtype = np.dtype(dtype)
12441248
self._dtype = dtype
12451249

12461250
@property
1247-
def dtype(self):
1251+
def dtype(self) -> np.dtype:
12481252
return self._dtype
12491253

1250-
def __array__(self, dtype=None):
1254+
def __array__(self, dtype: DTypeLike = None) -> np.ndarray:
12511255
if dtype is None:
12521256
dtype = self.dtype
12531257
array = self.array
@@ -1258,11 +1262,18 @@ def __array__(self, dtype=None):
12581262
return np.asarray(array.values, dtype=dtype)
12591263

12601264
@property
1261-
def shape(self):
1265+
def shape(self) -> Tuple[int]:
12621266
# .shape is broken on pandas prior to v0.15.2
12631267
return (len(self.array),)
12641268

1265-
def __getitem__(self, indexer):
1269+
def __getitem__(
1270+
self, indexer
1271+
) -> Union[
1272+
NumpyIndexingAdapter,
1273+
np.ndarray,
1274+
np.datetime64,
1275+
np.timedelta64,
1276+
]:
12661277
key = indexer.tuple
12671278
if isinstance(key, tuple) and len(key) == 1:
12681279
# unpack key so it can index a pandas.Index object (pandas.Index
@@ -1299,9 +1310,20 @@ def __getitem__(self, indexer):
12991310

13001311
return result
13011312

1302-
def transpose(self, order):
1313+
def transpose(self, order) -> pd.Index:
13031314
return self.array # self.array should be always one-dimensional
13041315

1305-
def __repr__(self):
1316+
def __repr__(self) -> str:
13061317
return ('%s(array=%r, dtype=%r)'
13071318
% (type(self).__name__, self.array, self.dtype))
1319+
1320+
def copy(self, deep: bool = True) -> 'PandasIndexAdapter':
1321+
# Not the same as just writing `self.array.copy(deep=deep)`, as
1322+
# shallow copies of the underlying numpy.ndarrays become deep ones
1323+
# upon pickling
1324+
# >>> len(pickle.dumps((self.array, self.array)))
1325+
# 4000281
1326+
# >>> len(pickle.dumps((self.array, self.array.copy(deep=False))))
1327+
# 8000341
1328+
array = self.array.copy(deep=True) if deep else self.array
1329+
return PandasIndexAdapter(array, self._dtype)

xarray/core/utils.py

+10
Original file line numberDiff line numberDiff line change
@@ -462,12 +462,22 @@ def __repr__(self: Any) -> str:
462462
class ReprObject:
463463
"""Object that prints as the given value, for use with sentinel values.
464464
"""
465+
__slots__ = ('_value', )
466+
465467
def __init__(self, value: str):
466468
self._value = value
467469

468470
def __repr__(self) -> str:
469471
return self._value
470472

473+
def __eq__(self, other) -> bool:
474+
if isinstance(other, ReprObject):
475+
return self._value == other._value
476+
return False
477+
478+
def __hash__(self) -> int:
479+
return hash((ReprObject, self._value))
480+
471481

472482
@contextlib.contextmanager
473483
def close_on_error(f):

xarray/core/variable.py

+1-8
Original file line numberDiff line numberDiff line change
@@ -1942,14 +1942,7 @@ def copy(self, deep=True, data=None):
19421942
data copied from original.
19431943
"""
19441944
if data is None:
1945-
if deep:
1946-
# self._data should be a `PandasIndexAdapter` instance at this
1947-
# point, which doesn't have a copy method, so make a deep copy
1948-
# of the underlying `pandas.MultiIndex` and create a new
1949-
# `PandasIndexAdapter` instance with it.
1950-
data = PandasIndexAdapter(self._data.array.copy(deep=True))
1951-
else:
1952-
data = self._data
1945+
data = self._data.copy(deep=deep)
19531946
else:
19541947
data = as_compatible_data(data)
19551948
if self.shape != data.shape:

xarray/tests/test_utils.py

+16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from collections import OrderedDict
22
from datetime import datetime
3+
from typing import Hashable
34

45
import numpy as np
56
import pandas as pd
@@ -179,6 +180,21 @@ def test_sorted_keys_dict(self):
179180
def test_repr_object():
180181
obj = utils.ReprObject('foo')
181182
assert repr(obj) == 'foo'
183+
assert isinstance(obj, Hashable)
184+
assert not isinstance(obj, str)
185+
186+
187+
def test_repr_object_magic_methods():
188+
o1 = utils.ReprObject('foo')
189+
o2 = utils.ReprObject('foo')
190+
o3 = utils.ReprObject('bar')
191+
o4 = 'foo'
192+
assert o1 == o2
193+
assert o1 != o3
194+
assert o1 != o4
195+
assert hash(o1) == hash(o2)
196+
assert hash(o1) != hash(o3)
197+
assert hash(o1) != hash(o4)
182198

183199

184200
def test_is_remote_uri():

xarray/tests/test_variable.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -477,8 +477,9 @@ def test_concat_mixed_dtypes(self):
477477
assert actual.dtype == object
478478

479479
@pytest.mark.parametrize('deep', [True, False])
480-
def test_copy(self, deep):
481-
v = self.cls('x', 0.5 * np.arange(10), {'foo': 'bar'})
480+
@pytest.mark.parametrize('astype', [float, int, str])
481+
def test_copy(self, deep, astype):
482+
v = self.cls('x', (0.5 * np.arange(10)).astype(astype), {'foo': 'bar'})
482483
w = v.copy(deep=deep)
483484
assert type(v) is type(w)
484485
assert_identical(v, w)

0 commit comments

Comments
 (0)