|
27 | 27 | ROOT_NODE_ID,
|
28 | 28 | DataIdType,
|
29 | 29 | DeserializeMapperType,
|
| 30 | + IterMethod, |
30 | 31 | KeyMapType,
|
31 | 32 | MapperCallbackType,
|
32 | 33 | PredicateCallbackType,
|
@@ -137,12 +138,44 @@ def last_child(self, kind: str | type[ANY_KIND]) -> Self | None:
|
137 | 138 | return n
|
138 | 139 | return None
|
139 | 140 |
|
| 141 | + def iterator( |
| 142 | + self, |
| 143 | + method: IterMethod = IterMethod.PRE_ORDER, |
| 144 | + *, |
| 145 | + add_self=False, |
| 146 | + kind: str | type[ANY_KIND] = ANY_KIND, |
| 147 | + ) -> Iterator[TypedNode[TData]]: |
| 148 | + """Return an iterator that walks the tree in the specified order.""" |
| 149 | + if kind is ANY_KIND: |
| 150 | + yield from super().iterator(method=method, add_self=add_self) |
| 151 | + return |
| 152 | + |
| 153 | + if add_self and self.kind == kind: |
| 154 | + yield self |
| 155 | + for n in super().iterator(method=method, add_self=False): |
| 156 | + if n.kind == kind: |
| 157 | + yield n |
| 158 | + return |
| 159 | + |
140 | 160 | def has_children(self, kind: str | type[ANY_KIND]) -> bool:
|
141 | 161 | """Return true if this node has one or more children."""
|
142 | 162 | if kind is ANY_KIND:
|
143 | 163 | return bool(self._children)
|
144 | 164 | return len(self.get_children(kind)) > 1
|
145 | 165 |
|
| 166 | + def count_descendants( |
| 167 | + self, *, leaves_only=False, kind: str | type[ANY_KIND] = ANY_KIND |
| 168 | + ) -> int: |
| 169 | + """Return number of descendant nodes, not counting self.""" |
| 170 | + if kind is ANY_KIND: |
| 171 | + return super().count_descendants(leaves_only=leaves_only) |
| 172 | + all = not leaves_only |
| 173 | + i = 0 |
| 174 | + for node in self.iterator(): |
| 175 | + if (all or not node._children) and node.kind == kind: |
| 176 | + i += 1 |
| 177 | + return i |
| 178 | + |
146 | 179 | def get_siblings(self, *, add_self=False, any_kind=False) -> list[Self]:
|
147 | 180 | """Return a list of all sibling entries of self (excluding self) if any."""
|
148 | 181 | if any_kind:
|
@@ -630,13 +663,30 @@ def last_child(self, kind: str | type[ANY_KIND]) -> TypedNode[TData] | None:
|
630 | 663 | return self.system_root.last_child(kind=kind)
|
631 | 664 |
|
632 | 665 | def iter_by_type(self, kind: str | type[ANY_KIND]) -> Iterator[TypedNode[TData]]:
|
| 666 | + """@deprecated: Use :meth:`iterator` with `kind` argument instead.""" |
| 667 | + yield from self.iterator(kind=kind) |
| 668 | + |
| 669 | + def iterator( |
| 670 | + self, |
| 671 | + method: IterMethod = IterMethod.PRE_ORDER, |
| 672 | + *, |
| 673 | + kind: str | type[ANY_KIND] = ANY_KIND, |
| 674 | + ) -> Iterator[TypedNode[TData]]: |
633 | 675 | if kind == ANY_KIND:
|
634 |
| - yield from self.iterator() |
635 |
| - for n in self.iterator(): |
| 676 | + yield from super().iterator(method=method) |
| 677 | + return |
| 678 | + |
| 679 | + for n in super().iterator(method=method): |
636 | 680 | if n._kind == kind:
|
637 | 681 | yield n
|
638 | 682 | return
|
639 | 683 |
|
| 684 | + def count_descendants( |
| 685 | + self, *, leaves_only=False, kind: str | type[ANY_KIND] = ANY_KIND |
| 686 | + ) -> int: |
| 687 | + """Return number of nodes, optionally restricted to type.""" |
| 688 | + return self.system_root.count_descendants(leaves_only=leaves_only, kind=kind) |
| 689 | + |
640 | 690 | def save(
|
641 | 691 | self,
|
642 | 692 | target: IO[str] | str | Path,
|
|
0 commit comments