Skip to content

Commit 6da8c2c

Browse files
authored
support datatree in assert_allclose (#10887)
* extend `_all_compat` to support functions as compat * extend the allclose tests to `DataTree` * support `DataTree` in `assert_allclose` * whats-new [skip-ci]
1 parent 85d9d2c commit 6da8c2c

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ New Features
1919
By `Stephan Hoyer <https://github.com/shoyer>`_.
2020
- The ``h5netcdf`` engine has support for pseudo ``NETCDF4_CLASSIC`` files, meaning variables and attributes are cast to supported types. Note that the saved files won't be recognized as genuine ``NETCDF4_CLASSIC`` files until ``h5netcdf`` adds support with version 1.7.0. (:issue:`10676`, :pull:`10686`).
2121
By `David Huard <https://github.com/huard>`_.
22+
- Support comparing :py:class:`DataTree` objects with :py:func:`testing.assert_allclose` (:pull:`10887`).
23+
By `Justus Magin <https://github.com/keewis>`_.
2224

2325
Breaking Changes
2426
~~~~~~~~~~~~~~~~

xarray/core/dataset.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,13 +1506,18 @@ def __delitem__(self, key: Hashable) -> None:
15061506
# https://github.com/python/mypy/issues/4266
15071507
__hash__ = None # type: ignore[assignment]
15081508

1509-
def _all_compat(self, other: Self, compat_str: str) -> bool:
1509+
def _all_compat(
1510+
self, other: Self, compat: str | Callable[[Variable, Variable], bool]
1511+
) -> bool:
15101512
"""Helper function for equals and identical"""
15111513

1512-
# some stores (e.g., scipy) do not seem to preserve order, so don't
1513-
# require matching order for equality
1514-
def compat(x: Variable, y: Variable) -> bool:
1515-
return getattr(x, compat_str)(y)
1514+
if not callable(compat):
1515+
compat_str = compat
1516+
1517+
# some stores (e.g., scipy) do not seem to preserve order, so don't
1518+
# require matching order for equality
1519+
def compat(x: Variable, y: Variable) -> bool:
1520+
return getattr(x, compat_str)(y)
15161521

15171522
return self._coord_names == other._coord_names and utils.dict_equiv(
15181523
self._variables, other._variables, compat=compat

xarray/testing/assertions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,11 @@ def compat_variable(a, b):
239239
b = getattr(b, "variable", b)
240240
return a.dims == b.dims and (a._data is b._data or equiv(a.data, b.data))
241241

242+
def compat_node(a, b):
243+
return a.ds._coord_names == b.ds._coord_names and utils.dict_equiv(
244+
a.variables, b.variables, compat=compat_variable
245+
)
246+
242247
if isinstance(a, Variable):
243248
allclose = compat_variable(a, b)
244249
assert allclose, formatting.diff_array_repr(a, b, compat=equiv)
@@ -255,6 +260,11 @@ def compat_variable(a, b):
255260
elif isinstance(a, Coordinates):
256261
allclose = utils.dict_equiv(a.variables, b.variables, compat=compat_variable)
257262
assert allclose, formatting.diff_coords_repr(a, b, compat=equiv)
263+
elif isinstance(a, DataTree):
264+
allclose = utils.dict_equiv(
265+
dict(a.subtree_with_keys), dict(b.subtree_with_keys), compat=compat_node
266+
)
267+
assert allclose, formatting.diff_datatree_repr(a, b, compat=equiv)
258268
else:
259269
raise TypeError(f"{type(a)} not supported by assertion comparison")
260270

xarray/tests/test_assertions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ def test_allclose_regression() -> None:
6262
xr.Coordinates({"x": [0, 3]}),
6363
id="Coordinates",
6464
),
65+
pytest.param(
66+
xr.DataTree.from_dict(
67+
{
68+
"/b": xr.Dataset({"a": ("x", [1e-17, 2]), "b": ("y", [-2e-18, 2])}),
69+
}
70+
),
71+
xr.DataTree.from_dict(
72+
{
73+
"/b": xr.Dataset({"a": ("x", [0, 2]), "b": ("y", [0, 1])}),
74+
}
75+
),
76+
id="DataTree",
77+
),
6578
),
6679
)
6780
def test_assert_allclose(obj1, obj2) -> None:

0 commit comments

Comments
 (0)