class TestGraph(unittest.TestCase): """ Test sort on graph. """ def setUp(self): """ Initialize the TestGraph class. """ self.objects = ["chaussures", "chaussettes", "slip", "pantalon", "ceinture", "chemise", "veste", "cravate"] self.dependancies = [ ("slip", "pantalon"), ("chemise", "cravate"), ("chemise", "pantalon"), ("pantalon", "ceinture"), ("chaussettes", "chaussures"), ("pantalon", "chaussures"), ("ceinture", "chaussures"), ("chemise", "veste"), ] self.sorted_objects = ["slip", "chaussettes", "chemise", "veste", "pantalon", "ceinture", "chaussures", "cravate"] self.graph = Graph() for o in self.objects: self.graph.add_node(GraphNode(o, None)) for d in self.dependancies: self.graph.add_link(d[0], d[1]) def test_raises(self): """ Method to test the raises. """ self.assertRaises(Exception, self.graph.add_node, object()) self.assertEqual(self.graph.find_node("bad"), None) self.assertRaises(Exception, self.graph.remove_node, "bad") self.assertRaises(ValueError, self.graph.add_node, self.graph._nodes[self.objects[0]]) self.assertRaises(Exception, self.graph.add_link, "bad", "bad") self.assertRaises(Exception, self.graph.add_link, self.sorted_objects[0], "bad") def test_static_sort(self): """ Method to test the static node sort. """ static_sort = [node[0] for node in self.graph.topological_sort()] self.assertTrue(set(static_sort).issubset(self.sorted_objects)) def test_dynamic_sort(self): """ Method to test the dynamic node sort. """ nnil = sorted([node.name for node in self.graph.available_nodes()]) self.assertEqual(nnil, ["chaussettes", "chemise", "slip"]) self.graph.remove_node("slip") nnil = sorted([node.name for node in self.graph.available_nodes()]) self.assertEqual(nnil, ["chaussettes", "chemise"]) self.graph.remove_node("chemise") nnil = sorted([node.name for node in self.graph.available_nodes()]) self.assertEqual(nnil, ["chaussettes", "cravate", "pantalon", "veste"]) self.graph.remove_node("ceinture") def test_layout(self): """ Method to test the layout creation. """ graph = Graph() self.assertEqual(sorted(graph.layout().keys()), []) graph.add_node(GraphNode("node1", None)) self.assertEqual(sorted(graph.layout().keys()), ["node1"]) graph.add_node(GraphNode("node2", None)) self.assertEqual(sorted(graph.layout().keys()), ["node1", "node2"]) self.assertTrue(set(self.graph.layout()).issubset(self.sorted_objects))
def _create_graph(self, box, prefix="", flatten=True, add_io=False, filter_inactive=False): """ Create a graph repesentation of a box. Parameters ---------- box: Pbox or Bbox (mandatory) a box from which we want to extract the graph representation. prefix: str (optional, default '') a prefix for the box names. flatten: bool (optional, default True) If True iterate through the sub-graph structures. add_io: bool (optional, default False) If True add the 'inputs' and 'outputs' nodes. filter_inactive: bool (optional, default False) If True filter inactive boxes. Returns ------- graph: Graph a graph representation of the input box. """ # Add the graph nodes graph = Graph() pboxes = {} for box_name in list(box._boxes.keys()): inner_box = box._boxes[box_name] if filter_inactive and not inner_box.active: continue if isinstance(inner_box, Pbox): if flatten: inner_prefix = prefix + "{0}.".format(box_name) sub_graph, inlinkreps, outlinkreps = self._create_graph( inner_box, inner_prefix, filter_inactive=filter_inactive) graph.add_graph(sub_graph) pboxes[box_name] = (sub_graph, inlinkreps, outlinkreps) else: graph.add_node(GraphNode(prefix + box_name, inner_box)) elif isinstance(inner_box, Bbox) or isinstance(inner_box, Ibox): graph.add_node(GraphNode(prefix + box_name, inner_box)) else: raise ValueError( "'{0}' is not a valid box type. Allowed types are '{1}', " "'{2}' or '{3}'.".format(type(inner_box), Bbox, Pbox, Ibox)) # Add io nodes if requested if add_io: graph.add_node(GraphNode(prefix + "inputs", None)) graph.add_node(GraphNode(prefix + "outputs", None)) # Add the graph links input_linkreps = {} output_linkreps = {} for linkrep in box._links: # Parse link src_box_name, src_ctrl, dest_box_name, dest_ctrl = parse_link( linkrep) # Pbox special case: flatening if src_box_name in pboxes: src_box_name = "{0}.{1}".format( src_box_name, pboxes[src_box_name][2][src_ctrl][0]) if dest_box_name in pboxes: dest_box_name = "{0}.{1}".format( dest_box_name, pboxes[dest_box_name][1][dest_ctrl][0]) # Add an inner link, skip inpout/output links, check that no # inactive box is involved in this link if src_box_name == "": input_linkreps[src_ctrl] = (dest_box_name, dest_ctrl) if add_io: graph.add_link(prefix + "inputs", prefix + dest_box_name) elif dest_box_name == "": output_linkreps[dest_ctrl] = (src_box_name, src_ctrl) if add_io: graph.add_link(prefix + src_box_name, prefix + "outputs") elif (filter_inactive and ( prefix + src_box_name not in graph._nodes or prefix + dest_box_name not in graph._nodes)): continue else: graph.add_link(prefix + src_box_name, prefix + dest_box_name) return graph, input_linkreps, output_linkreps