Skip to content

Commit 2df31b7

Browse files
authored
Fix DataTree.from_dict to be insensitive to insertion order (#9292)
* regression test * fix by sorting before insertion * whatsnew * test nodes retain insertion order within a group * make test pass by sorting by depth
1 parent 8c8d097 commit 2df31b7

File tree

3 files changed

+32
-1
lines changed

3 files changed

+32
-1
lines changed

doc/whats-new.rst

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ Deprecations
3535
Bug fixes
3636
~~~~~~~~~
3737

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

3941
Documentation
4042
~~~~~~~~~~~~~

xarray/core/datatree.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -1102,9 +1102,14 @@ def from_dict(
11021102
else:
11031103
obj = cls(name=name, data=root_data, parent=None, children=None)
11041104

1105+
def depth(item) -> int:
1106+
pathstr, _ = item
1107+
return len(NodePath(pathstr).parts)
1108+
11051109
if d:
11061110
# Populate tree with children determined from data_objects mapping
1107-
for path, data in d.items():
1111+
# Sort keys by depth so as to insert nodes from root first (see GH issue #9276)
1112+
for path, data in sorted(d.items(), key=depth):
11081113
# Create and set new node
11091114
node_name = NodePath(path).name
11101115
if isinstance(data, DataTree):

xarray/tests/test_datatree.py

+24
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,30 @@ def test_roundtrip_unnamed_root(self, simple_datatree):
561561
roundtrip = DataTree.from_dict(dt.to_dict())
562562
assert roundtrip.equals(dt)
563563

564+
def test_insertion_order(self):
565+
# regression test for GH issue #9276
566+
reversed = DataTree.from_dict(
567+
{
568+
"/Homer/Lisa": xr.Dataset({"age": 8}),
569+
"/Homer/Bart": xr.Dataset({"age": 10}),
570+
"/Homer": xr.Dataset({"age": 39}),
571+
"/": xr.Dataset({"age": 83}),
572+
}
573+
)
574+
expected = DataTree.from_dict(
575+
{
576+
"/": xr.Dataset({"age": 83}),
577+
"/Homer": xr.Dataset({"age": 39}),
578+
"/Homer/Lisa": xr.Dataset({"age": 8}),
579+
"/Homer/Bart": xr.Dataset({"age": 10}),
580+
}
581+
)
582+
assert reversed.equals(expected)
583+
584+
# Check that Bart and Lisa's order is still preserved within the group,
585+
# despite 'Bart' coming before 'Lisa' when sorted alphabetically
586+
assert list(reversed["Homer"].children.keys()) == ["Lisa", "Bart"]
587+
564588

565589
class TestDatasetView:
566590
def test_view_contents(self):

0 commit comments

Comments
 (0)