Skip to content

Commit

Permalink
Fix DataTree.from_dict to be insensitive to insertion order (#9292)
Browse files Browse the repository at this point in the history
* regression test

* fix by sorting before insertion

* whatsnew

* test nodes retain insertion order within a group

* make test pass by sorting by depth
  • Loading branch information
TomNicholas authored Jul 31, 2024
1 parent 8c8d097 commit 2df31b7
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 1 deletion.
2 changes: 2 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ Deprecations
Bug fixes
~~~~~~~~~

- Fix bug causing `DataTree.from_dict` to be sensitive to insertion order (:issue:`9276`, :pull:`9292`).
By `Tom Nicholas <https://github.com/TomNicholas>`_.

Documentation
~~~~~~~~~~~~~
Expand Down
7 changes: 6 additions & 1 deletion xarray/core/datatree.py
Original file line number Diff line number Diff line change
Expand Up @@ -1102,9 +1102,14 @@ def from_dict(
else:
obj = cls(name=name, data=root_data, parent=None, children=None)

def depth(item) -> int:
pathstr, _ = item
return len(NodePath(pathstr).parts)

if d:
# Populate tree with children determined from data_objects mapping
for path, data in d.items():
# Sort keys by depth so as to insert nodes from root first (see GH issue #9276)
for path, data in sorted(d.items(), key=depth):
# Create and set new node
node_name = NodePath(path).name
if isinstance(data, DataTree):
Expand Down
24 changes: 24 additions & 0 deletions xarray/tests/test_datatree.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,30 @@ def test_roundtrip_unnamed_root(self, simple_datatree):
roundtrip = DataTree.from_dict(dt.to_dict())
assert roundtrip.equals(dt)

def test_insertion_order(self):
# regression test for GH issue #9276
reversed = DataTree.from_dict(
{
"/Homer/Lisa": xr.Dataset({"age": 8}),
"/Homer/Bart": xr.Dataset({"age": 10}),
"/Homer": xr.Dataset({"age": 39}),
"/": xr.Dataset({"age": 83}),
}
)
expected = DataTree.from_dict(
{
"/": xr.Dataset({"age": 83}),
"/Homer": xr.Dataset({"age": 39}),
"/Homer/Lisa": xr.Dataset({"age": 8}),
"/Homer/Bart": xr.Dataset({"age": 10}),
}
)
assert reversed.equals(expected)

# Check that Bart and Lisa's order is still preserved within the group,
# despite 'Bart' coming before 'Lisa' when sorted alphabetically
assert list(reversed["Homer"].children.keys()) == ["Lisa", "Bart"]


class TestDatasetView:
def test_view_contents(self):
Expand Down

0 comments on commit 2df31b7

Please sign in to comment.