From 484ded4baa58bc4e02862523b744ef7e122c5684 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Tue, 4 Aug 2015 11:43:39 -0700 Subject: [PATCH] Enable conversion of the tree nodes into a digraph Just like it's useful to be able to translate a execution graph into a dot diagram, the same usefulness can be helpful for the engine scoping hierarchy that is created, to make it easily possible to do this provide a tree method that converts itself (and its children) into a direct graph which can then easily be exported as a dot diagram (and then rendered as needed). Change-Id: I0addc2dee4cdce03ee5f33832a419303abc77db4 --- taskflow/tests/unit/test_types.py | 21 +++++++++++++++++++++ taskflow/types/tree.py | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/taskflow/tests/unit/test_types.py b/taskflow/tests/unit/test_types.py index 9399c893..178b9af3 100644 --- a/taskflow/tests/unit/test_types.py +++ b/taskflow/tests/unit/test_types.py @@ -499,6 +499,27 @@ CEO self.assertEqual(['mammal', 'reptile', 'horse', 'primate', 'monkey', 'human'], things) + def test_to_diagraph(self): + root = self._make_species() + g = root.to_digraph() + self.assertEqual(root.child_count(only_direct=False) + 1, len(g)) + for node in root.dfs_iter(include_self=True): + self.assertIn(node.item, g) + self.assertEqual([], g.predecessors('animal')) + self.assertEqual(['animal'], g.predecessors('reptile')) + self.assertEqual(['primate'], g.predecessors('human')) + self.assertEqual(['mammal'], g.predecessors('primate')) + self.assertEqual(['animal'], g.predecessors('mammal')) + self.assertEqual(['mammal', 'reptile'], g.successors('animal')) + + def test_to_digraph_retains_metadata(self): + root = tree.Node("chickens", alive=True) + dead_chicken = tree.Node("chicken.1", alive=False) + root.add(dead_chicken) + g = root.to_digraph() + self.assertEqual(g.node['chickens'], {'alive': True}) + self.assertEqual(g.node['chicken.1'], {'alive': False}) + class OrderedSetTest(test.TestCase): diff --git a/taskflow/types/tree.py b/taskflow/types/tree.py index 56c96bbb..d6a0df2c 100644 --- a/taskflow/types/tree.py +++ b/taskflow/types/tree.py @@ -22,6 +22,7 @@ import os import six +from taskflow.types import graph from taskflow.utils import iter_utils from taskflow.utils import misc @@ -388,3 +389,20 @@ class Node(object): return _BFSIter(self, include_self=include_self, right_to_left=right_to_left) + + def to_digraph(self): + """Converts this node + its children into a ordered directed graph. + + The graph returned will have the same structure as the + this node and its children (and tree node metadata will be translated + into graph node metadata). + + :returns: a directed graph + :rtype: :py:class:`taskflow.types.graph.OrderedDiGraph` + """ + g = graph.OrderedDiGraph() + for node in self.bfs_iter(include_self=True, right_to_left=True): + g.add_node(node.item, attr_dict=node.metadata) + if node is not self: + g.add_edge(node.parent.item, node.item) + return g