Closed flamingbear closed 1 week ago
This might need to be a separate issue, but assign used to update in place rather than create a full new DataTree and this might be why? This is what I'm seeing now.
bart = xr.DataTree(name="Bart")
lisa = xr.DataTree(name="Lisa")
homer = xr.DataTree(name="Homer", children={"Lisa": lisa})
lisa.parent = homer
print(homer)
try:
homer.parent = lisa
except Exception:
print("that excepts as expected")
homer = homer.assign({"bart": bart})
print(homer)
# This shouldn't work
homer.parent = lisa
# This looks bad
print(homer)
And the output
<xarray.DataTree 'Homer'>
Group: /
└── Group: /Lisa
that excepts as expected
<xarray.DataTree 'Homer'>
Group: /
├── Group: /Lisa
└── Group: /
<xarray.DataTree 'Homer'>
Group: /Lisa/Homer
├── Group: /Lisa/Homer/Lisa
└── Group: /
Thanks again @flamingbear ! I think I've tracked these down, and they are both the same issue. Basically there is a bug in the new implementation of ._replace_node
(introduced in #9063).
What happens is that inside ._replace_node
we assign to self._children
instead of self.children
, which therefore skips a bunch of _pre_attach
and other stuff in treenode.py
that ensures that all the paths are consistent. Without this then if you print the new merged_children
inside .update
you see this
In [3]: homer.assign(Bart=bart)
{'Lisa': <xarray.DataTree 'Lisa'>
Group: /Lisa, 'Bart': <xarray.DataTree 'Bart'>
Group: /}
Notice that Bart
has a path of /
, not /Bart
as it should to be consistent with /Lisa
. This means the .path
attributes of the new_children
have not yet been altered correctly to fit into the tree, and it's not safe to assign to self._children
yet.
I think we should just assign to self.children
instead.
Another way to say this is: Assigning directly to self._children
is a bug because it's not enough to just say "these are the new children", you also have to tell those children who their new parent is, and that step is being skipped.
FYI @shoyer
simply changing the _replace_node datatree.py L773 with this diff, does fix the "root names"
- self._children = children
+ self.children = children
I'm still seeing the assign act strange (allowing cycles)
lisa = xr.DataTree(name="Lisa")
homer = xr.DataTree(name="Homer", children={"Lisa": lisa})
homer = homer.assign({})
homer.parent = lisa
print(homer)
<xarray.DataTree 'Homer'>
Group: /Lisa/Homer
└── Group: /Lisa/Homer/Lisa
I'm pretty sure you told me exactly how to fix this yesterday, but it didn't sink in until last night, I'll see if I can do this or at least throw something up to discuss.
So This was my confusion from the old code to the new w/r/t assign. It's not creating cycles. I just missed that the (current) assign behavior is creating a new homer
so it's fine to make lisa
his parent.
Anyway this will change again with #9297, but the original multiple root groups can be fixed with that one liner and I'll put that up now.
And actually you can close this with #9297 I'll just suggest the extra assert
closed in #9243
What happened?
Reviewing documentation for hierarchical-data.rst I saw the abe/herbert example didn't look right, updated the
abe.assign()
->abe = abe.assign()
and it still looked wrongWhat did you expect to happen?
I expected not to see two root groups.
Minimal Complete Verifiable Example
MVCE confirmation
Relevant log output
No response
Anything else we need to know?
it is failing the update or the assign (but because assign uses update)
Environment