diff --git a/doc/whats-new.rst b/doc/whats-new.rst index afb8a9b21a8..3ad2f268f37 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -55,8 +55,11 @@ Bug fixes due to a ``datetime`` issue in NumPy (:issue:`2334`). By `Graham Inggs `_. - Fixed bug in ``combine_by_coords()`` causing a `ValueError` if the input had - an unused dimension with coordinates which were not monotonic (:issue`3150`). + an unused dimension with coordinates which were not monotonic (:issue:`3150`). By `Tom Nicholas `_. +- Fixed crash when applying ``distributed.Client.compute()`` to a DataArray + (:issue:`3171`). By `Guido Imperiale `_. + .. _whats-new.0.12.3: diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index f993888c8f4..0e28613323e 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -300,7 +300,7 @@ def _replace( self, variable: Variable = None, coords=None, - name: Union[Hashable, None, ReprObject] = __default, + name: Optional[Hashable] = __default, ) -> 'DataArray': if variable is None: variable = self.variable @@ -313,7 +313,7 @@ def _replace( def _replace_maybe_drop_dims( self, variable: Variable, - name: Union[str, None, utils.ReprObject] = __default + name: Optional[Hashable] = __default ) -> 'DataArray': if variable.dims == self.dims and variable.shape == self.shape: coords = self._coords.copy() @@ -356,7 +356,7 @@ def _to_temp_dataset(self) -> Dataset: def _from_temp_dataset( self, dataset: Dataset, - name: Union[Hashable, ReprObject] = __default + name: Hashable = __default ) -> 'DataArray': variable = dataset._variables.pop(_THIS_ARRAY) coords = dataset._variables diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 8ce30a3c517..08c911f5e4a 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -462,12 +462,22 @@ def __repr__(self: Any) -> str: class ReprObject: """Object that prints as the given value, for use with sentinel values. """ + __slots__ = ('_value', ) + def __init__(self, value: str): self._value = value def __repr__(self) -> str: return self._value + def __eq__(self, other) -> bool: + if isinstance(other, ReprObject): + return self._value == other._value + return False + + def __hash__(self) -> int: + return hash((ReprObject, self._value)) + @contextlib.contextmanager def close_on_error(f): diff --git a/xarray/tests/test_utils.py b/xarray/tests/test_utils.py index bcd960e4e29..ce4c5cc8198 100644 --- a/xarray/tests/test_utils.py +++ b/xarray/tests/test_utils.py @@ -1,5 +1,6 @@ from collections import OrderedDict from datetime import datetime +from typing import Hashable import numpy as np import pandas as pd @@ -179,6 +180,21 @@ def test_sorted_keys_dict(self): def test_repr_object(): obj = utils.ReprObject('foo') assert repr(obj) == 'foo' + assert isinstance(obj, Hashable) + assert not isinstance(obj, str) + + +def test_repr_object_magic_methods(): + o1 = utils.ReprObject('foo') + o2 = utils.ReprObject('foo') + o3 = utils.ReprObject('bar') + o4 = 'foo' + assert o1 == o2 + assert o1 != o3 + assert o1 != o4 + assert hash(o1) == hash(o2) + assert hash(o1) != hash(o3) + assert hash(o1) != hash(o4) def test_is_remote_uri():