-
Notifications
You must be signed in to change notification settings - Fork 42
DataTree.lineage should be renamed to .parents #286
Changes from all commits
ec5457a
cdf5ad3
423e68a
9a91490
52bc31b
543402c
2d465d8
91854bc
4cf5130
d3ea0db
a1cdfb4
1e45e3d
057a638
6d1d787
fbdc558
6375923
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -132,4 +132,5 @@ dmypy.json | |
# version | ||
_version.py | ||
|
||
.vscode | ||
# Ignore vscode specific settings | ||
.vscode/ |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -121,8 +121,7 @@ def _check_loop(self, new_parent: Tree | None) -> None: | |||
) | ||||
|
||||
def _is_descendant_of(self, node: Tree) -> bool: | ||||
_self, *lineage = list(node.lineage) | ||||
return any(n is self for n in lineage) | ||||
return any(n is self for n in node.parents) | ||||
|
||||
def _detach(self, parent: Tree | None) -> None: | ||||
if parent is not None: | ||||
|
@@ -236,26 +235,53 @@ def _post_attach_children(self: Tree, children: Mapping[str, Tree]) -> None: | |||
"""Method call after attaching `children`.""" | ||||
pass | ||||
|
||||
def iter_lineage(self: Tree) -> Iterator[Tree]: | ||||
def _iter_parents(self: Tree) -> Iterator[Tree]: | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kept the private |
||||
"""Iterate up the tree, starting from the current node.""" | ||||
node: Tree | None = self | ||||
node: Tree | None = self.parent | ||||
while node is not None: | ||||
yield node | ||||
node = node.parent | ||||
|
||||
def iter_lineage(self: Tree) -> Tuple[Tree, ...]: | ||||
"""Iterate up the tree, starting from the current node.""" | ||||
from warnings import warn | ||||
|
||||
warn( | ||||
"`iter_lineage` has been deprecated, and in the future will raise an error." | ||||
"Please use `parents` from now on.", | ||||
DeprecationWarning, | ||||
) | ||||
return tuple((self, *self.parents)) | ||||
|
||||
@property | ||||
def lineage(self: Tree) -> Tuple[Tree, ...]: | ||||
"""All parent nodes and their parent nodes, starting with the closest.""" | ||||
return tuple(self.iter_lineage()) | ||||
from warnings import warn | ||||
|
||||
warn( | ||||
"`lineage` has been deprecated, and in the future will raise an error." | ||||
"Please use `parents` from now on.", | ||||
DeprecationWarning, | ||||
) | ||||
return self.iter_lineage() | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Call chain: |
||||
|
||||
@property | ||||
def parents(self: Tree) -> Tuple[Tree, ...]: | ||||
"""All parent nodes and their parent nodes, starting with the closest.""" | ||||
return tuple(self._iter_parents()) | ||||
|
||||
@property | ||||
def ancestors(self: Tree) -> Tuple[Tree, ...]: | ||||
"""All parent nodes and their parent nodes, starting with the most distant.""" | ||||
if self.parent is None: | ||||
return (self,) | ||||
else: | ||||
ancestors = tuple(reversed(list(self.lineage))) | ||||
return ancestors | ||||
|
||||
from warnings import warn | ||||
|
||||
warn( | ||||
"`ancestors` has been deprecated, and in the future will raise an error." | ||||
"Please use `parents`. Example: `tuple(reversed(node.parents))`", | ||||
DeprecationWarning, | ||||
) | ||||
return tuple((*reversed(self.parents), self)) | ||||
|
||||
@property | ||||
def root(self: Tree) -> Tree: | ||||
|
@@ -351,7 +377,7 @@ def level(self: Tree) -> int: | |||
depth | ||||
width | ||||
""" | ||||
return len(self.ancestors) - 1 | ||||
return len(self.parents) | ||||
|
||||
@property | ||||
def depth(self: Tree) -> int: | ||||
|
@@ -591,9 +617,9 @@ def path(self) -> str: | |||
if self.is_root: | ||||
return "/" | ||||
else: | ||||
root, *ancestors = self.ancestors | ||||
root, *ancestors = tuple(reversed(self.parents)) | ||||
# don't include name of root because (a) root might not have a name & (b) we want path relative to root. | ||||
names = [node.name for node in ancestors] | ||||
names = [*(node.name for node in ancestors), self.name] | ||||
return "/" + "/".join(names) | ||||
|
||||
def relative_to(self: NamedNode, other: NamedNode) -> str: | ||||
|
@@ -608,7 +634,7 @@ def relative_to(self: NamedNode, other: NamedNode) -> str: | |||
) | ||||
|
||||
this_path = NodePath(self.path) | ||||
if other.path in list(ancestor.path for ancestor in self.lineage): | ||||
if other.path in list(parent.path for parent in (self, *self.parents)): | ||||
return str(this_path.relative_to(other.path)) | ||||
else: | ||||
common_ancestor = self.find_common_ancestor(other) | ||||
|
@@ -623,18 +649,17 @@ def find_common_ancestor(self, other: NamedNode) -> NamedNode: | |||
|
||||
Raise ValueError if they are not in the same tree. | ||||
""" | ||||
common_ancestor = None | ||||
for node in other.iter_lineage(): | ||||
if node.path in [ancestor.path for ancestor in self.ancestors]: | ||||
common_ancestor = node | ||||
break | ||||
if self is other: | ||||
return self | ||||
|
||||
if not common_ancestor: | ||||
raise NotFoundInTreeError( | ||||
"Cannot find common ancestor because nodes do not lie within the same tree" | ||||
) | ||||
other_paths = [op.path for op in other.parents] | ||||
for parent in (self, *self.parents): | ||||
if parent.path in other_paths: | ||||
return parent | ||||
|
||||
return common_ancestor | ||||
raise NotFoundInTreeError( | ||||
"Cannot find common ancestor because nodes do not lie within the same tree" | ||||
) | ||||
|
||||
def _path_to_ancestor(self, ancestor: NamedNode) -> NodePath: | ||||
"""Return the relative path from this node to the given ancestor node""" | ||||
|
@@ -643,12 +668,12 @@ def _path_to_ancestor(self, ancestor: NamedNode) -> NodePath: | |||
raise NotFoundInTreeError( | ||||
"Cannot find relative path to ancestor because nodes do not lie within the same tree" | ||||
) | ||||
if ancestor.path not in list(a.path for a in self.ancestors): | ||||
if ancestor.path not in list(a.path for a in (self, *self.parents)): | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know if the project has some test coverage tool, but I'm pretty sure this change is actually useless, as the case of the node being compared has been handled previously in the |
||||
raise NotFoundInTreeError( | ||||
"Cannot find relative path to ancestor because given node is not an ancestor of this node" | ||||
) | ||||
|
||||
lineage_paths = list(ancestor.path for ancestor in self.lineage) | ||||
generation_gap = list(lineage_paths).index(ancestor.path) | ||||
path_upwards = "../" * generation_gap if generation_gap > 0 else "/" | ||||
parents_paths = list(parent.path for parent in (self, *self.parents)) | ||||
generation_gap = list(parents_paths).index(ancestor.path) | ||||
path_upwards = "../" * generation_gap if generation_gap > 0 else "." | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same, this path was causing me issues, but the datatree/datatree/tests/test_datatree.py Line 98 in 66397e8
|
||||
return NodePath(path_upwards) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A node's parents do not include the node itself, in opposition to
lineage
.Note:
lineage
is still tested intest_lineage