def test_add_subgraph_escape_name(self): fac = PydotFactory() g = fac.get_graph() fac.add_subgraph_to_graph(g, 'graph') self.assertEqual(1, len(g.get_subgraph_list())) self.assertEqual('cluster_graph_', g.get_subgraph_list()[0].get_name()) self.assertEqual('graph_', g.get_subgraph_list()[0].get_label())
def test_add_node_escape_name(self): fac = PydotFactory() g = fac.get_graph() fac.add_node_to_graph(g, 'graph') self.assertEqual(1, len(g.get_nodes())) self.assertEqual('graph_', g.get_nodes()[0].get_name()) self.assertEqual('graph_', g.get_nodes()[0].get_label())
def test_add_edge(self): fac = PydotFactory() g = fac.get_graph() fac.add_node_to_graph(g, 'foo') fac.add_node_to_graph(g, 'bar') fac.add_edge_to_graph(g, 'foo', 'bar') self.assertEqual(2, len(g.get_nodes())) self.assertEqual(1, len(g.get_edges())) self.assertEqual('foo', g.get_edges()[0].get_source()) self.assertEqual('bar', g.get_edges()[0].get_destination())
def generate_dotcode_from_capability_info(): spec_index, errors = spec_index_from_service() assert not errors dotcode_factory = PydotFactory() dotgraph = dotcode_factory.get_graph(rankdir="BT") for name in spec_index.interfaces: dotcode_factory.add_node_to_graph(dotgraph, nodename=str(name), shape="box") for name in spec_index.semantic_interfaces: dotcode_factory.add_node_to_graph(dotgraph, nodename=str(name), shape="box") for name, provider in spec_index.providers.items(): dotcode_factory.add_node_to_graph(dotgraph, nodename=str(name), shape="ellipse") dotcode_factory.add_edge_to_graph(dotgraph, str(name), str(provider.implements), label="provides") for dep in provider.dependencies: dotcode_factory.add_edge_to_graph(dotgraph, str(name), str(dep), label="requires") return dotcode_factory.create_dot(dotgraph)
def test_create_dot(self): fac = PydotFactory() g = fac.get_graph() fac.add_node_to_graph(g, 'foo') fac.add_node_to_graph(g, 'edge') fac.add_edge_to_graph(g, 'foo', 'edge') fac.add_subgraph_to_graph(g, 'foo') snippets = ['digraph graphname {\n\tgraph [rankdir=TB, ranksep="0.2", rank=same, compound=True];\n\tnode [label="\\N"];\n\tgraph [bb="', '"];\n\tsubgraph cluster_foo {\n\t\tgraph [', '];\n\t}\n\tfoo [label=foo, shape=box, pos="', 'edge_ [label=edge_, shape=box, pos="', 'foo -> edge_', '"];\n}\n'] result = fac.create_dot(g) for sn in snippets: self.assertTrue(sn in result, '%s \nmissing in\n %s' % (sn, result))
def test_create_dot(self): fac = PydotFactory() g = fac.get_graph() fac.add_node_to_graph(g, 'foo') fac.add_node_to_graph(g, 'edge') fac.add_edge_to_graph(g, 'foo', 'edge') fac.add_subgraph_to_graph(g, 'foo') snippets = [ 'digraph graphname {\n\tgraph [', 'rankdir=TB', 'compound=True', 'rank=same', 'node [label="\\N"]', 'subgraph cluster_foo {\n\t\tgraph [', 'foo\t [', 'label=foo', 'shape=box', 'pos="', 'edge_\t [', 'label=edge_', 'foo -> edge_\t [', '"];\n}\n' ] result = fac.create_dot(g) for sn in snippets: self.assertTrue(sn in result, '%s \nmissing in\n %s' % (sn, result))
def test_create_dot(self): fac = PydotFactory() g = fac.get_graph() fac.add_node_to_graph(g, 'foo') fac.add_node_to_graph(g, 'edge') fac.add_edge_to_graph(g, 'foo', 'edge') fac.add_subgraph_to_graph(g, 'foo') snippets = [ 'digraph graphname { graph [', 'rankdir=TB', 'compound=True', 'rank=same', 'node [label="\\N"]', 'subgraph cluster_foo { graph [', 'foo [', 'label=foo', 'shape=box', 'pos="', 'edge_ [', 'label=edge_', 'foo -> edge_ [', '"]; }' ] result = fac.create_dot(g) # get rid of version specific whitespaces result = re.sub('[\n\t ]+', ' ', result) for sn in snippets: self.assertTrue(sn in result, '%s \nmissing in\n %s' % (sn, result))
def test_create_dot(self): fac = PydotFactory() g = fac.get_graph() fac.add_node_to_graph(g, 'foo') fac.add_node_to_graph(g, 'edge') fac.add_edge_to_graph(g, 'foo', 'edge') fac.add_subgraph_to_graph(g, 'foo') snippets = ['digraph graphname {\n\tgraph [', 'rankdir=TB', 'compound=True', 'rank=same', 'node [label="\\N"]', 'subgraph cluster_foo {\n\t\tgraph [', 'foo\t [', 'label=foo', 'shape=box', 'pos="', 'edge_\t [', 'label=edge_', 'foo -> edge_\t [', '"];\n}\n'] result = fac.create_dot(g) for sn in snippets: self.assertTrue(sn in result, '%s \nmissing in\n %s' % (sn, result))
def generate_dotcode_from_capability_info(spec_index, running_providers): dotcode_factory = PydotFactory() dotgraph = dotcode_factory.get_graph(rankdir="BT") interface_graphs = {} # Draw plain interfaces for name in spec_index.interfaces: providers = [ k for k, v in spec_index.providers.items() if v.implements == name ] # Only create a subgraph if it has providers if providers: interface_graphs[name] = dotcode_factory.add_subgraph_to_graph( dotgraph, str(name) + "_group", subgraphlabel='') # Draw box for interface graph = interface_graphs.get(name, dotgraph) dotcode_factory.add_node_to_graph(graph, nodename=str(name), shape="box") # Draw semantic interfaces for name, interface in spec_index.semantic_interfaces.items(): providers = [ k for k, v in spec_index.providers.items() if v.implements == name ] # Only create a subgraph if it has providers if providers: interface_graphs[name] = dotcode_factory.add_subgraph_to_graph( dotgraph, str(name) + "_group", subgraphlabel='') graph = interface_graphs.get(name, dotgraph) # Draw box for semantic interface dotcode_factory.add_node_to_graph(graph, nodename=str(name), shape="box") # Make edge to interface it redefines, if it exists if interface.redefines in spec_index.interfaces: dotcode_factory.add_edge_to_graph(dotgraph, str(name), str(interface.redefines), label="redefines") # Draw providers interfaces = dict(spec_index.interfaces) interfaces.update(spec_index.semantic_interfaces) for name, provider in spec_index.providers.items(): # Get subgraph of interface this provider implements graph = interface_graphs[provider.implements] # Get the default provider for the interface this provider implements default_provider = interfaces[provider.implements].default_provider provider_name = name # Add annotaion if this is the default provider if default_provider != 'unknown' and default_provider == name: provider_name += " (default)" # If it is running, make it green if name in running_providers: dotcode_factory.add_node_to_graph(graph, nodename=str(name), nodelabel=str(provider_name), shape="ellipse", color="green") # Else no color else: dotcode_factory.add_node_to_graph(graph, nodename=str(name), nodelabel=str(provider_name), shape="ellipse") # Add edges to the interface, provider paris this provider depends on for dep, relationship in provider.dependencies.items(): if relationship.preferred_provider is not None: dotcode_factory.add_edge_to_graph( dotgraph, str(name), str(relationship.preferred_provider), label="requires") elif spec_index.interfaces[ relationship. capability_name].default_provider != 'unknown': dotcode_factory.add_edge_to_graph( dotgraph, str(name), str(spec_index.interfaces[ relationship.capability_name].default_provider), label="requires") return dotcode_factory.create_dot(dotgraph)
class DotFileGraph: """The DotFileGraph class provides the logic for loading a dot file into memory and providing the ability to generate a selected portion of the graph into dot code. """ def __init__(self, dotFile, aboveDistance=1, belowDistance=1): """ * dotFile -- is the path to the dot file to load * aboveDistance -- the default distance above the node to display * belowDistance -- the default distance below the node to display """ self.__dotFile = dotFile self.__selectedNode = "" # No node selected by default self.__aboveDistance = aboveDistance self.__belowDistance = belowDistance # Factory used to generate dot code self.__dotcodeFactory = PydotFactory() # List of all nodes in the graph (updated once file is loaded) self.__allNodes = None # List of graph nodes and edges to display self.nodes = [] self.edges = [] # Load the initial dot file self.__loadDotFile() def getNodes(self): """Get the list of all nodes in the graph.""" return self.__allNodes def getSelectedNode(self): """Get the name of the currently selected node.""" return self.__selectedNode def setSelectedNode(self, node): """Set the currently selected node. * node -- the newly selected node """ self.__selectedNode = node self.__loadDotFile() def getAboveDistance(self): """Get the distance above the node that is being displayed.""" return self.__aboveDistance def setAboveDistance(self, distance): """Set the distance above the node that is being displayed. * distance -- the new distance above the node to display """ self.__aboveDistance = distance self.__loadDotFile() def getBelowDistance(self): """Get the distance below the node that is being displayed.""" return self.__belowDistance def setBelowDistance(self, distance): """Set the distance below the node that is being displayed. * distance -- the new distance below the node to display """ self.__belowDistance = distance self.__loadDotFile() def getDotCode(self, orientation='LR', rank='same', ranksep=0.2, rankdir='TB', simplify=True): """Get the dot code for this graph. * orientation -- the orientation of the dot figure (UD, or LR) * rank -- the rank (none, same, min, max, source, sink) * ranksep -- vertical distance between layers * rankdir -- the direction of layout: TB (top-bottom), LR (left-right) * simplify -- True to remove double edges """ # create the graph dotGraph = self.__dotcodeFactory.get_graph(rank=rank, ranksep=ranksep, simplify=simplify, rankdir=orientation) # Add all nodes to the graph if self.nodes is not None: for node in self.nodes: color = "blue" if node == self.__selectedNode else None self.__dotcodeFactory.add_node_to_graph(dotGraph, nodename=node, nodelabel=node, shape='ellipse', color=color) # Add all edges to the graph if self.edges is not None: for edge in self.edges: self.__dotcodeFactory.add_edge_to_graph(dotGraph, edge.start, edge.end, label=edge.label) # Convert the dot graph into dot code return self.__dotcodeFactory.create_dot(dotGraph) def __loadDotFile(self): """Load a graph from a dot file and prune out nodes and edges based on the distance above and below the currently selected node. """ # Load the dot file into memory self.__graph = pgv.AGraph(self.__dotFile) self.__allNodes = self.__graph.nodes() # Prune the graph, as desired if len(self.__selectedNode) > 0: neighbors = self.__getNodeNeighbors(self.__selectedNode, self.__aboveDistance, self.__belowDistance) # Remove all non-neighbor nodes nodes = self.__graph.nodes() for node in nodes: if node not in neighbors: self.__graph.delete_node(node) # Grab the set of nodes to display self.nodes = self.__graph.nodes() # Create the edges to display self.edges = [] for start, end in self.__graph.edges(): self.edges.append(Edge(start, end)) def __getNodeNeighbors(self, node, numAbove, numBelow): """Get the neighbors (above and below) to the given node. * node -- the name of the node * numAbove -- the number of levels above the node to include * numBelow -- the number of levels below the node to include """ parents = self.__getNodeParents(node, numAbove) children = self.__getNodeChildren(node, numBelow) return parents + children + [node] def __getNodeParents(self, node, level): """Get the parents (up to a certain level away) of the given node. * node -- the name of the node * level -- the maximum levels away from the node to include """ if level <= 0: return [] allNodes = [] # Add all nodes one level above the current node parents = self.__graph.predecessors(node) for subNode in parents: subNodes = self.__getNodeParents(subNode, level - 1) allNodes.append(subNode) allNodes.extend(subNodes) return list(set(allNodes)) def __getNodeChildren(self, node, level): """Get the children (up to a certain level away) of the given node. * node -- the name of the node * level -- the maximum levels away from the node to include """ if level <= 0: return [] allNodes = [] # Add all nodes one level below the current node parents = self.__graph.successors(node) for subNode in parents: subNodes = self.__getNodeChildren(subNode, level - 1) allNodes.append(subNode) allNodes.extend(subNodes) return list(set(allNodes))
def test_get_graph(self): fac = PydotFactory() g = fac.get_graph() self.assertEqual('same', g.get_rank()) self.assertEqual('digraph', g.get_graph_type())
def generate_dotcode_from_capability_info(spec_index, running_providers): dotcode_factory = PydotFactory() dotgraph = dotcode_factory.get_graph(rankdir="BT") interface_graphs = {} # Draw plain interfaces for name in spec_index.interfaces: providers = [k for k, v in spec_index.providers.items() if v.implements == name] # Only create a subgraph if it has providers if providers: interface_graphs[name] = dotcode_factory.add_subgraph_to_graph( dotgraph, str(name) + "_group", subgraphlabel="" ) # Draw box for interface graph = interface_graphs.get(name, dotgraph) dotcode_factory.add_node_to_graph(graph, nodename=str(name), shape="box") # Draw semantic interfaces for name, interface in spec_index.semantic_interfaces.items(): providers = [k for k, v in spec_index.providers.items() if v.implements == name] # Only create a subgraph if it has providers if providers: interface_graphs[name] = dotcode_factory.add_subgraph_to_graph( dotgraph, str(name) + "_group", subgraphlabel="" ) graph = interface_graphs.get(name, dotgraph) # Draw box for semantic interface dotcode_factory.add_node_to_graph(graph, nodename=str(name), shape="box") # Make edge to interface it redefines, if it exists if interface.redefines in spec_index.interfaces: dotcode_factory.add_edge_to_graph(dotgraph, str(name), str(interface.redefines), label="redefines") # Draw providers interfaces = dict(spec_index.interfaces) interfaces.update(spec_index.semantic_interfaces) for name, provider in spec_index.providers.items(): # Get subgraph of interface this provider implements graph = interface_graphs[provider.implements] # Get the default provider for the interface this provider implements default_provider = interfaces[provider.implements].default_provider provider_name = name # Add annotaion if this is the default provider if default_provider != "unknown" and default_provider == name: provider_name += " (default)" # If it is running, make it green if name in running_providers: dotcode_factory.add_node_to_graph( graph, nodename=str(name), nodelabel=str(provider_name), shape="ellipse", color="green" ) # Else no color else: dotcode_factory.add_node_to_graph(graph, nodename=str(name), nodelabel=str(provider_name), shape="ellipse") # Add edges to the interface, provider paris this provider depends on for dep, relationship in provider.dependencies.items(): if relationship.preferred_provider is not None: dotcode_factory.add_edge_to_graph( dotgraph, str(name), str(relationship.preferred_provider), label="requires" ) elif spec_index.interfaces[relationship.capability_name].default_provider != "unknown": dotcode_factory.add_edge_to_graph( dotgraph, str(name), str(spec_index.interfaces[relationship.capability_name].default_provider), label="requires", ) return dotcode_factory.create_dot(dotgraph)
def test_get_graph(self): fac = PydotFactory() g = fac.get_graph() self.assertEquals('same', g.get_rank()) self.assertEquals('digraph', g.get_graph_type())