def test_repr(): """Node representation.""" root = Node("root") s0 = Node("sub0", parent=root) s1 = Node("sub1", parent=root, foo=42, bar="c0fe") eq_(repr(root), "Node('/root')") eq_(repr(s0), "Node('/root/sub0')") eq_(repr(s1), "Node('/root/sub1', bar='c0fe', foo=42)")
def test_tree2(): """Tree2.""" root = Node("root") s0 = Node("sub0", parent=root, edge=2) Node("sub0B", parent=s0, foo=4, edge=109) Node("sub0A", parent=s0, edge="") s1 = Node("sub1", parent=root, edge="") Node("sub1A", parent=s1, edge=7) Node("sub1B", parent=s1, edge=8) s1c = Node("sub1C", parent=s1, edge=22) Node("sub1Ca", parent=s1c, edge=42) def nodenamefunc(node): return '%s:%s' % (node.name, node.depth) def edgeattrfunc(node, child): return 'label="%s:%s"' % (node.name, child.name) r = DotExporter(root, options=["rankdir=LR;"], nodenamefunc=nodenamefunc, nodeattrfunc=lambda node: "shape=box", edgeattrfunc=edgeattrfunc) r.to_dotfile(join(GENPATH, "tree2.dot")) assert cmp(join(GENPATH, "tree2.dot"), join(REFPATH, "tree2.dot"))
def test_levelgrouporder(): """LevelGroupOrderIter.""" f = Node("f") b = Node("b", parent=f) a = Node("a", parent=b) d = Node("d", parent=b) c = Node("c", parent=d) e = Node("e", parent=d) g = Node("g", parent=f) i = Node("i", parent=g) h = Node("h", parent=i) eq_(list(LevelGroupOrderIter(f)), [(f, ), (b, g), (a, d, i), (c, e, h)]) eq_(list(LevelGroupOrderIter(f, maxlevel=0)), []) eq_(list(LevelGroupOrderIter(f, maxlevel=3)), [(f, ), (b, g), (a, d, i)]) eq_( list(LevelGroupOrderIter(f, filter_=lambda n: n.name not in ('e', 'g'))), [(f, ), (b, ), (a, d, i), (c, h)]) eq_(list(LevelGroupOrderIter(f, stop=lambda n: n.name == 'd')), [(f, ), (b, g), (a, i), (h, )]) it = LevelGroupOrderIter(f) eq_(next(it), (f, )) eq_(next(it), (b, g))
def test_recursion_detection(): """Recursion detection.""" root = Node("root") s0 = Node("sub0", parent=root) Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) # try recursion assert root.parent is None try: root.parent = root except LoopError as exc: eq_(str(exc), "Cannot set parent. Node('/root') cannot be parent of itself.") assert root.parent is None else: assert False assert root.parent is None try: root.parent = s0a except LoopError as exc: eq_(str(exc), ("Cannot set parent. Node('/root') is parent of Node('/root/sub0/sub0A').")) assert root.parent is None else: assert False assert s0.parent is root try: s0.parent = s0a except LoopError as exc: eq_(str(exc), ("Cannot set parent. Node('/root/sub0') is parent of Node('/root/sub0/sub0A').")) assert s0.parent is root else: assert False
def test_tree_png(): """Tree to png.""" root = Node("root") s0 = Node("sub0", parent=root) Node("sub0B", parent=s0) Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) Node("sub1A", parent=s1) Node("sub1B", parent=s1) s1c = Node("sub1C", parent=s1) Node("sub1Ca", parent=s1c) DotExporter(root).to_picture(join(GENPATH, "tree1.png"))
def test_tree1(): """Tree1.""" root = Node("root") s0 = Node("sub0", parent=root) Node("sub0B", parent=s0) Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) Node("sub1A", parent=s1) Node("sub1B", parent=s1) s1c = Node("sub1C", parent=s1) Node("sub1Ca", parent=s1c) DotExporter(root).to_dotfile(join(GENPATH, "tree1.dot")) assert cmp(join(GENPATH, "tree1.dot"), join(REFPATH, "tree1.dot"))
def test_find_by_attr(): f = Node("f") b = Node("b", parent=f) Node("a", parent=b) d = Node("d", parent=b) c = Node("c", parent=d, foo=4) Node("e", parent=d) g = Node("g", parent=f) i = Node("i", parent=g) Node("h", parent=i) eq_(find_by_attr(f, "d"), d) eq_(find_by_attr(f, name="foo", value=4), c) eq_(find_by_attr(f, name="foo", value=8), None)
def test_post_order_iter(): """Post-Order Iterator.""" f = Node("f") b = Node("b", parent=f) a = Node("a", parent=b) d = Node("d", parent=b) c = Node("c", parent=d) e = Node("e", parent=d) g = Node("g", parent=f) i = Node("i", parent=g) h = Node("h", parent=i) result = [node.name for node in PostOrderIter(f)] expected = ['a', 'c', 'e', 'd', 'b', 'h', 'i', 'g', 'f'] eq_(result, expected)
def test_find(): f = Node("f") b = Node("b", parent=f) Node("a", parent=b) d = Node("d", parent=b) Node("c", parent=d) Node("e", parent=d) g = Node("g", parent=f) i = Node("i", parent=g) Node("h", parent=i) eq_(find(f, lambda n: n.name == "d"), d) eq_(find(f, lambda n: n.name == "z"), None) with assert_raises(CountError, ( "Expecting 1 elements at maximum, but found 5. " "(Node('/f/b'), Node('/f/b/a'), Node('/f/b/d'), Node('/f/b/d/c'), Node('/f/b/d/e'))")): find(f, lambda n: b in n.path)
def test_detach_children(): root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1a = Node("sub1A", parent=s1) s1b = Node("sub1B", parent=s1) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.descendants, (s0, s0b, s0a, s1, s1a, s1b, s1c, s1ca)) del s0.children eq_(root.descendants, (s0, s1, s1a, s1b, s1c, s1ca)) del s1.children eq_(root.descendants, (s0, s1))
def test_dict_exporter_node(): """Dict Exporter.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root, foo="bar") s1a = Node("sub1A", parent=s1) s1b = Node("sub1B", parent=s1) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) exporter = DictExporter() eq_( exporter.export(root), { 'name': 'root', 'children': [{ 'name': 'sub0', 'children': [{ 'name': 'sub0B' }, { 'name': 'sub0A' }] }, { 'name': 'sub1', 'foo': 'bar', 'children': [{ 'name': 'sub1A' }, { 'name': 'sub1B' }, { 'name': 'sub1C', 'children': [{ 'name': 'sub1Ca' }] }] }] })
def test_dict_exporter_filter(): """Dict Exporter.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root, foo="bar") s1a = Node("sub1A", parent=s1) s1b = Node("sub1B", parent=s1) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) exporter = DictExporter( attriter=lambda attrs: [(k, v) for k, v in attrs if k == "name"]) eq_( exporter.export(root), { 'name': 'root', 'children': [{ 'name': 'sub0', 'children': [{ 'name': 'sub0B' }, { 'name': 'sub0A' }] }, { 'name': 'sub1', 'children': [{ 'name': 'sub1A' }, { 'name': 'sub1B' }, { 'name': 'sub1C', 'children': [{ 'name': 'sub1Ca' }] }] }] })
def test_descendants(): """Node.descendants.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.descendants, tuple([s0, s0b, s0a, s1, s1c, s1ca])) eq_(s1.descendants, tuple([s1c, s1ca])) eq_(s1c.descendants, tuple([s1ca])) eq_(s1ca.descendants, tuple())
def test_findall_by_attr(): f = Node("f") b = Node("b", parent=f) Node("a", parent=b) d = Node("d", parent=b) Node("c", parent=d) Node("e", parent=d) eq_(findall_by_attr(f, "d"), (d,)) with assert_raises(CountError, ( "Expecting at least 1 elements, but found 0.")): findall_by_attr(f, "z", mincount=1)
def test_postorder(): """PostOrderIter.""" f = Node("f") b = Node("b", parent=f) a = Node("a", parent=b) d = Node("d", parent=b) c = Node("c", parent=d) e = Node("e", parent=d) g = Node("g", parent=f) i = Node("i", parent=g) h = Node("h", parent=i) eq_(list(PostOrderIter(f)), [a, c, e, d, b, h, i, g, f]) eq_(list(PostOrderIter(f, maxlevel=0)), []) eq_(list(PostOrderIter(f, maxlevel=3)), [a, d, b, i, g, f]) eq_(list(PostOrderIter(f, filter_=lambda n: n.name not in ('e', 'g'))), [a, c, d, b, h, i, f]) eq_(list(PostOrderIter(f, stop=lambda n: n.name == 'd')), [a, b, h, i, g, f]) it = PostOrderIter(f) eq_(next(it), a) eq_(next(it), c)
def test_levelorder(): """LevelOrderIter.""" f = Node("f") b = Node("b", parent=f) a = Node("a", parent=b) d = Node("d", parent=b) c = Node("c", parent=d) e = Node("e", parent=d) g = Node("g", parent=f) i = Node("i", parent=g) h = Node("h", parent=i) eq_(list(LevelOrderIter(f)), [f, b, g, a, d, i, c, e, h]) eq_(list(LevelOrderIter(f, maxlevel=0)), []) eq_(list(LevelOrderIter(f, maxlevel=3)), [f, b, g, a, d, i]) eq_(list(LevelOrderIter(f, filter_=lambda n: n.name not in ('e', 'g'))), [f, b, a, d, i, c, h]) eq_(list(LevelOrderIter(f, stop=lambda n: n.name == 'd')), [f, b, g, a, i, h]) it = LevelOrderIter(f) eq_(next(it), f) eq_(next(it), b)
def test_siblings(): """Node.siblings.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.siblings, tuple()) eq_(s0.siblings, tuple([s1])) eq_(s0b.siblings, tuple([s0a])) eq_(s0a.siblings, tuple([s0b])) eq_(s1.siblings, tuple([s0])) eq_(s1c.siblings, tuple()) eq_(s1ca.siblings, tuple())
def test_root(): """Node.root.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.root, root) eq_(s0.root, root) eq_(s0b.root, root) eq_(s0a.root, root) eq_(s1.root, root) eq_(s1c.root, root) eq_(s1ca.root, root)
def test_ancestors(): """Node.ancestors.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.ancestors, tuple()) eq_(s0.ancestors, tuple([root])) eq_(s0b.ancestors, tuple([root, s0])) eq_(s0a.ancestors, tuple([root, s0])) eq_(s1ca.ancestors, tuple([root, s1, s1c])) # deprecated typo eq_(s1ca.anchestors, tuple([root, s1, s1c]))
def test_zigzaggroup(): """ZigZagGroupIter.""" f = Node("f") b = Node("b", parent=f) a = Node("a", parent=b) d = Node("d", parent=b) c = Node("c", parent=d) e = Node("e", parent=d) g = Node("g", parent=f) i = Node("i", parent=g) h = Node("h", parent=i) eq_(list(ZigZagGroupIter(f)), [(f, ), (g, b), (a, d, i), (h, e, c)]) eq_(list(ZigZagGroupIter(f, maxlevel=0)), []) eq_(list(ZigZagGroupIter(f, maxlevel=3)), [(f, ), (g, b), (a, d, i)]) eq_(list(ZigZagGroupIter(f, filter_=lambda n: n.name not in ('e', 'g'))), [(f, ), (b, ), (a, d, i), (h, c)]) eq_(list(ZigZagGroupIter(f, stop=lambda n: n.name == 'd')), [(f, ), (g, b), (a, i), (h, )]) it = ZigZagGroupIter(f) eq_(next(it), (f, )) eq_(next(it), (g, b))
def test_height(): """Node.height.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.height, 3) eq_(s0.height, 1) eq_(s0b.height, 0) eq_(s0a.height, 0) eq_(s1.height, 2) eq_(s1c.height, 1) eq_(s1ca.height, 0)
def test_depth(): """Node.depth.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.depth, 0) eq_(s0.depth, 1) eq_(s0b.depth, 2) eq_(s0a.depth, 2) eq_(s1.depth, 1) eq_(s1c.depth, 2) eq_(s1ca.depth, 3)
def test_is_root(): """Node.is_root.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.is_root, True) eq_(s0.is_root, False) eq_(s0b.is_root, False) eq_(s0a.is_root, False) eq_(s1.is_root, False) eq_(s1c.is_root, False) eq_(s1ca.is_root, False)
def test_findall(): f = Node("f") b = Node("b", parent=f) a = Node("a", parent=b) d = Node("d", parent=b) c = Node("c", parent=d) e = Node("e", parent=d) eq_(findall(f, filter_=lambda node: node.name in ("a", "b")), (b, a)) eq_(findall(f, filter_=lambda node: d in node.path), (d, c, e)) with assert_raises(CountError, ( "Expecting at least 4 elements, but found 3. " "(Node('/f/b/d'), Node('/f/b/d/c'), Node('/f/b/d/e'))")): findall(f, filter_=lambda node: d in node.path, mincount=4) with assert_raises(CountError, ( "Expecting 2 elements at maximum, but found 3. " "(Node('/f/b/d'), Node('/f/b/d/c'), Node('/f/b/d/e'))")): findall(f, filter_=lambda node: d in node.path, maxcount=2)
def test_stackoverflow(): """Example from stackoverflow.""" udo = Node("Udo") marc = Node("Marc", parent=udo) Node("Lian", parent=marc) dan = Node("Dan", parent=udo) Node("Jet", parent=dan) Node("Jan", parent=dan) joe = Node("Joe", parent=dan) eq_(str(udo), "Node('/Udo')") eq_(str(joe), "Node('/Udo/Dan/Joe')") eq_(["%s%s" % (pre, node.name) for pre, fill, node in RenderTree(udo)], [ u"Udo", u"├── Marc", u"│ └── Lian", u"└── Dan", u" ├── Jet", u" ├── Jan", u" └── Joe", ]) eq_(str(dan.children), "(Node('/Udo/Dan/Jet'), Node('/Udo/Dan/Jan'), Node('/Udo/Dan/Joe'))")
def test_parent_child(): """A tree parent and child attributes.""" root = Node("root") s0 = Node("sub0", parent=root) s0b = Node("sub0B", parent=s0) s0a = Node("sub0A", parent=s0) s1 = Node("sub1", parent=root) s1a = Node("sub1A", parent=s1) s1b = Node("sub1B", parent=s1) s1c = Node("sub1C", parent=s1) s1ca = Node("sub1Ca", parent=s1c) eq_(root.parent, None) eq_(root.children, tuple([s0, s1])) eq_(s0.parent, root) eq_(s0.children, tuple([s0b, s0a])) eq_(s0b.parent, s0) eq_(s0b.children, tuple()) eq_(s0a.parent, s0) eq_(s0a.children, tuple()) eq_(s1.parent, root) eq_(s1.children, tuple([s1a, s1b, s1c])) eq_(s1a.parent, s1) eq_(s1a.children, tuple()) eq_(s1b.parent, s1) eq_(s1b.children, tuple()) eq_(s1c.parent, s1) eq_(s1c.children, tuple([s1ca])) eq_(s1ca.parent, s1c) eq_(s1ca.children, tuple()) # change parent s1ca.parent = s0 eq_(root.parent, None) eq_(root.children, tuple([s0, s1])) eq_(s0.parent, root) eq_(s0.children, tuple([s0b, s0a, s1ca])) eq_(s0b.parent, s0) eq_(s0b.children, tuple()) eq_(s0a.parent, s0) eq_(s0a.children, tuple()) eq_(s1.parent, root) eq_(s1.children, tuple([s1a, s1b, s1c])) eq_(s1a.parent, s1) eq_(s1a.children, tuple()) eq_(s1b.parent, s1) eq_(s1b.children, tuple()) eq_(s1c.parent, s1) eq_(s1c.children, tuple()) eq_(s1ca.parent, s0) eq_(s1ca.children, tuple()) # break tree into two s1.parent = None eq_(root.parent, None) eq_(root.children, tuple([s0])) eq_(s0.parent, root) eq_(s0.children, tuple([s0b, s0a, s1ca])) eq_(s0b.parent, s0) eq_(s0b.children, tuple()) eq_(s0a.parent, s0) eq_(s0a.children, tuple()) eq_(s1.parent, None) eq_(s1.children, tuple([s1a, s1b, s1c])) eq_(s1a.parent, s1) eq_(s1a.children, tuple()) eq_(s1b.parent, s1) eq_(s1b.children, tuple()) eq_(s1c.parent, s1) eq_(s1c.children, tuple()) eq_(s1ca.parent, s0) eq_(s1ca.children, tuple()) # set to the same s1b.parent = s1 eq_(root.parent, None) eq_(root.children, tuple([s0])) eq_(s0.parent, root) eq_(s0.children, tuple([s0b, s0a, s1ca])) eq_(s0b.parent, s0) eq_(s0b.children, tuple()) eq_(s0a.parent, s0) eq_(s0a.children, tuple()) eq_(s1.parent, None) eq_(s1.children, tuple([s1a, s1b, s1c])) eq_(s1a.parent, s1) eq_(s1a.children, tuple()) eq_(s1b.parent, s1) eq_(s1b.children, tuple()) eq_(s1c.parent, s1) eq_(s1c.children, tuple()) eq_(s1ca.parent, s0) eq_(s1ca.children, tuple())
def test_anyname(): """Support any type as name.""" myroot = Node([1, 2, 3]) Node('/foo', parent=myroot) eq_(str(myroot), "Node('/[1, 2, 3]')")
def test_children_setter_large(): root = Node("root") s0 = Node("sub0") s0b = Node("sub0B") s0a = Node("sub0A") s1 = Node("sub1") s1a = Node("sub1A") s1b = Node("sub1B") s1c = Node("sub1C") s1ca = Node("sub1Ca") root.children = [s0, s1] eq_(root.descendants, (s0, s1)) s0.children = [s0a, s0b] eq_(root.descendants, (s0, s0a, s0b, s1)) s1.children = [s1a, s1b, s1c] eq_(root.descendants, (s0, s0a, s0b, s1, s1a, s1b, s1c)) with assert_raises(TypeError, "'Node' object is not iterable"): s1.children = s1ca eq_(root.descendants, (s0, s0a, s0b, s1, s1a, s1b, s1c))
def test_node_children_type(): root = Node("root") with assert_raises(TreeError, "Cannot add non-node object 'string'. It is not a subclass of 'NodeMixin'."): root.children = ["string"]
def test_node_children_multiple(): root = Node("root") sub = Node("sub") with assert_raises(TreeError, "Cannot add node Node('/sub') multiple times as child."): root.children = [sub, sub]