Skip to content
This repository was archived by the owner on Oct 24, 2024. It is now read-only.

Commit 19572e2

Browse files
authored
Add leaves property (#177)
* test * implementation of leaves * add leaves to public API * whatsnew
1 parent a5838c1 commit 19572e2

File tree

4 files changed

+33
-5
lines changed

4 files changed

+33
-5
lines changed

datatree/tests/test_treenode.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,18 @@ def test_descendants(self):
326326
for node, expected_name in zip(descendants, expected):
327327
assert node.name == expected_name
328328

329+
def test_leaves(self):
330+
tree, _ = create_test_tree()
331+
leaves = tree.leaves
332+
expected = [
333+
"d",
334+
"f",
335+
"g",
336+
"i",
337+
]
338+
for node, expected_name in zip(leaves, expected):
339+
assert node.name == expected_name
340+
329341

330342
class TestRenderTree:
331343
def test_render_nodetree(self):

datatree/treenode.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,14 +267,27 @@ def root(self: Tree) -> Tree:
267267

268268
@property
269269
def is_root(self) -> bool:
270-
"""Whether or not this node is the tree root."""
270+
"""Whether this node is the tree root."""
271271
return self.parent is None
272272

273273
@property
274274
def is_leaf(self) -> bool:
275-
"""Whether or not this node is a leaf node."""
275+
"""
276+
Whether this node is a leaf node.
277+
278+
Leaf nodes are defined as nodes which have no children.
279+
"""
276280
return self.children == {}
277281

282+
@property
283+
def leaves(self: Tree) -> Tuple[Tree, ...]:
284+
"""
285+
All leaf nodes.
286+
287+
Leaf nodes are defined as nodes which have no children.
288+
"""
289+
return tuple([node for node in self.subtree if node.is_leaf])
290+
278291
@property
279292
def siblings(self: Tree) -> OrderedDict[str, Tree]:
280293
"""
@@ -307,7 +320,7 @@ def subtree(self: Tree) -> Iterator[Tree]:
307320
return iterators.PreOrderIter(self)
308321

309322
@property
310-
def descendants(self: Tree) -> Tuple[Tree]:
323+
def descendants(self: Tree) -> Tuple[Tree, ...]:
311324
"""
312325
Child nodes and all their child nodes.
313326
@@ -319,7 +332,7 @@ def descendants(self: Tree) -> Tuple[Tree]:
319332
"""
320333
all_nodes = tuple(self.subtree)
321334
this_node, *descendants = all_nodes
322-
return tuple(descendants) # type: ignore[return-value]
335+
return tuple(descendants)
323336

324337
def _pre_detach(self: Tree, parent: Tree) -> None:
325338
"""Method call before detaching from `parent`."""
@@ -563,7 +576,7 @@ def find_common_ancestor(self, other: NamedNode) -> NamedNode:
563576

564577
if not common_ancestor:
565578
raise NotFoundInTreeError(
566-
"Cannot find relative path because nodes do not lie within the same tree"
579+
"Cannot find common ancestor because nodes do not lie within the same tree"
567580
)
568581

569582
return common_ancestor

docs/source/api.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Attributes relating to the recursive tree-like structure of a ``DataTree``.
3030
DataTree.root
3131
DataTree.is_root
3232
DataTree.is_leaf
33+
DataTree.leaves
3334
DataTree.subtree
3435
DataTree.descendants
3536
DataTree.siblings

docs/source/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ New Features
2929
By `Tom Nicholas <https://github.com/TomNicholas>`_.
3030
- Added a new :py:meth:`DataTree.descendants` property (:pull:`170`).
3131
By `Tom Nicholas <https://github.com/TomNicholas>`_.
32+
- Added a :py:meth:`DataTree.leaves` property (:pull:`177`).
33+
By `Tom Nicholas <https://github.com/TomNicholas>`_.
3234

3335
Breaking changes
3436
~~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)