Skip to content

Commit bd01d09

Browse files
committed
chg: usr: add func to filter duplicate child docs with same prefix
* in case of duplicate child prefix, keep the one with longest path, which is what we want for target docs in subtree path * add a test func and logging calls, set filter result to info Signed-off-by: Stephen L Arnold <sarnold@vctlabs.com>
1 parent 4be9952 commit bd01d09

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

doorstop/core/tests/test_tree.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,25 @@ def test_from_list_discard(self):
162162
self.assertEqual(2, len(tree))
163163
self.assertTrue(tree.validate())
164164

165+
def test_from_list_filter(self):
166+
"""Verify same prefix child is filtered."""
167+
a = MockDocumentSkip(EMPTY)
168+
a.prefix = "A" # type: ignore
169+
b = MockDocumentSkip(EMPTY)
170+
b.prefix = "B" # type: ignore
171+
b.parent = "A" # type: ignore
172+
c = MockDocumentSkip(EMPTY)
173+
c.prefix = "B" # type: ignore
174+
c.parent = "A" # type: ignore
175+
c.path = c.path + "/cempty" # type: ignore
176+
docs = [a, b, c]
177+
tree = Tree.from_list(docs)
178+
self.assertEqual(2, len(tree))
179+
self.assertTrue(tree.validate())
180+
self.assertIn('/cempty', tree.children[0].document.path)
181+
#print(tree)
182+
#print(tree.children)
183+
165184
def test_from_list_no_root(self):
166185
"""Verify an error occurs when the tree has no root."""
167186
a = MockDocumentSkip(EMPTY)

doorstop/core/tree.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ class Tree(BaseValidatable): # pylint: disable=R0902
4141

4242
@staticmethod
4343
def from_list(documents, root=None):
44-
"""Initialize a new tree from a list of documents.
44+
"""
45+
Initialize a new tree from a list of documents.
4546
4647
:param documents: list of :class:`~doorstop.core.document.Document`
4748
:param root: path to root of the project
@@ -50,8 +51,28 @@ def from_list(documents, root=None):
5051
cannot be built
5152
5253
:return: new :class:`~doorstop.core.tree.Tree`
53-
5454
"""
55+
56+
def _filter_children_by_prefix(docs_from: List) -> List:
57+
"""
58+
If child documents are found, filter them by document prefix
59+
and only keep the document with longer path when a duplicate
60+
prefix is found.
61+
62+
:param documents: list of :class:`~doorstop.core.document.Document`
63+
:return: filtered list of :class:`~doorstop.core.document.Document`
64+
"""
65+
seen: Dict = {}
66+
for doc in docs_from:
67+
if doc.prefix in seen and len(doc.path) > len(seen[doc.prefix].path):
68+
log.info("filtered from tree: {}".format(seen[doc.prefix]))
69+
seen[doc.prefix] = doc # update previous doc, or
70+
if doc.prefix not in seen:
71+
seen.update({doc.prefix: doc}) # add new doc
72+
log.info("filtered result: {}".format(seen))
73+
return list(seen.values())
74+
75+
5576
if not documents:
5677
return Tree(document=None, root=root)
5778
unplaced = list(documents)
@@ -65,6 +86,8 @@ def from_list(documents, root=None):
6586
else:
6687
raise DoorstopError("no root document")
6788

89+
unplaced = _filter_children_by_prefix(unplaced)
90+
6891
while unplaced:
6992
count = len(unplaced)
7093
for document in list(unplaced):

0 commit comments

Comments
 (0)