Add node removal/disassociate functions
When a node desires to be removed from its parent (or a parent wants to remove a child) it is quite useful to provide functions that do just this so that nodes can remove themselves or there children when this kind of usage is desired. Change-Id: I0071e9a7e15219e0cb7b92779e4f5a08596e5d34
This commit is contained in:
@@ -113,6 +113,44 @@ class TreeTest(test.TestCase):
|
||||
root = tree.Node("josh")
|
||||
self.assertTrue(root.empty())
|
||||
|
||||
def test_removal(self):
|
||||
root = self._make_species()
|
||||
self.assertIsNotNone(root.remove('reptile'))
|
||||
self.assertRaises(ValueError, root.remove, 'reptile')
|
||||
self.assertIsNone(root.find('reptile'))
|
||||
|
||||
def test_removal_direct(self):
|
||||
root = self._make_species()
|
||||
self.assertRaises(ValueError, root.remove, 'human',
|
||||
only_direct=True)
|
||||
|
||||
def test_removal_self(self):
|
||||
root = self._make_species()
|
||||
n = root.find('horse')
|
||||
self.assertIsNotNone(n.parent)
|
||||
n.remove('horse', include_self=True)
|
||||
self.assertIsNone(n.parent)
|
||||
self.assertIsNone(root.find('horse'))
|
||||
|
||||
def test_disassociate(self):
|
||||
root = self._make_species()
|
||||
n = root.find('horse')
|
||||
self.assertIsNotNone(n.parent)
|
||||
c = n.disassociate()
|
||||
self.assertEqual(1, c)
|
||||
self.assertIsNone(n.parent)
|
||||
self.assertIsNone(root.find('horse'))
|
||||
|
||||
def test_disassociate_many(self):
|
||||
root = self._make_species()
|
||||
n = root.find('horse')
|
||||
n.parent.add(n)
|
||||
n.parent.add(n)
|
||||
c = n.disassociate()
|
||||
self.assertEqual(3, c)
|
||||
self.assertIsNone(n.parent)
|
||||
self.assertIsNone(root.find('horse'))
|
||||
|
||||
def test_not_empty(self):
|
||||
root = self._make_species()
|
||||
self.assertFalse(root.empty())
|
||||
|
||||
@@ -149,6 +149,44 @@ class Node(object):
|
||||
return n
|
||||
return None
|
||||
|
||||
def disassociate(self):
|
||||
"""Removes this node from its parent (if any).
|
||||
|
||||
:returns: occurences of this node that were removed from its parent.
|
||||
"""
|
||||
occurrences = 0
|
||||
if self.parent is not None:
|
||||
p = self.parent
|
||||
self.parent = None
|
||||
# Remove all instances of this node from its parent.
|
||||
while True:
|
||||
try:
|
||||
p._children.remove(self)
|
||||
except ValueError:
|
||||
break
|
||||
else:
|
||||
occurrences += 1
|
||||
return occurrences
|
||||
|
||||
def remove(self, item, only_direct=False, include_self=True):
|
||||
"""Removes a item from this nodes children.
|
||||
|
||||
This will search not only this node but also any children nodes and
|
||||
finally if nothing is found then a value error is raised instead of
|
||||
the normally returned *removed* node object.
|
||||
|
||||
:param item: item to lookup.
|
||||
:param only_direct: only look at current node and its direct children.
|
||||
:param include_self: include the current node during searching.
|
||||
"""
|
||||
node = self.find(item, only_direct=only_direct,
|
||||
include_self=include_self)
|
||||
if node is None:
|
||||
raise ValueError("Item '%s' not found to remove" % item)
|
||||
else:
|
||||
node.disassociate()
|
||||
return node
|
||||
|
||||
def __contains__(self, item):
|
||||
"""Returns whether item exists in this node or this nodes children.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user