From 9cf7a04a3e0c3d64fdc79419f631cd8fd0461c3c Mon Sep 17 00:00:00 2001 From: Valentin Lorentz <vlorentz@softwareheritage.org> Date: Mon, 24 Feb 2020 15:59:14 +0100 Subject: [PATCH] Add method MerkleNode.iter_tree, to visit all nodes in the subtree of a node. --- swh/model/merkle.py | 16 +++++++++++++++- swh/model/tests/test_merkle.py | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/swh/model/merkle.py b/swh/model/merkle.py index 31be3d17..9d97efdc 100644 --- a/swh/model/merkle.py +++ b/swh/model/merkle.py @@ -8,7 +8,7 @@ import abc import collections -from typing import List, Optional +from typing import Iterator, List, Optional, Set def deep_update(left, right): @@ -273,6 +273,20 @@ class MerkleNode(dict, metaclass=abc.ABCMeta): for child in self.values(): child.reset_collect() + def iter_tree(self) -> Iterator['MerkleNode']: + """Yields all children nodes, recursively. Common nodes are + deduplicated. + """ + yield from self._iter_tree(set()) + + def _iter_tree( + self, seen: Set[bytes]) -> Iterator['MerkleNode']: + if self.hash not in seen: + seen.add(self.hash) + yield self + for child in self.values(): + yield from child._iter_tree(seen=seen) + class MerkleLeaf(MerkleNode): """A leaf to a Merkle tree. diff --git a/swh/model/tests/test_merkle.py b/swh/model/tests/test_merkle.py index dc7da63b..734f7c03 100644 --- a/swh/model/tests/test_merkle.py +++ b/swh/model/tests/test_merkle.py @@ -184,6 +184,10 @@ class TestMerkleNode(unittest.TestCase): collected2 = self.root.collect() self.assertEqual(collected2, {}) + def test_iter_tree(self): + nodes = list(self.root.iter_tree()) + self.assertCountEqual(nodes, self.nodes.values()) + def test_get(self): for key in (b'a', b'b', b'c'): self.assertEqual(self.root[key], self.nodes[b'root/' + key]) -- GitLab