Merge "adding support for networkx 2.0"
This commit is contained in:
commit
4e98d787ec
@ -82,9 +82,6 @@ class TopologyApis(EntityGraphApisBase):
|
||||
is_admin_project,
|
||||
root_id)
|
||||
|
||||
alarms = graph.get_vertices(query_dict=ALARMS_ALL_QUERY)
|
||||
graph.update_vertices(alarms)
|
||||
|
||||
return graph.json_output_graph()
|
||||
|
||||
def _get_topology_for_specific_project(self,
|
||||
@ -179,7 +176,7 @@ class TopologyApis(EntityGraphApisBase):
|
||||
def _create_graph_of_connected_components(self, ga, tmp_graph, root):
|
||||
return ga.subgraph(self._topology_for_unrooted_graph(ga,
|
||||
tmp_graph,
|
||||
root))
|
||||
root)).copy()
|
||||
|
||||
def _topology_for_unrooted_graph(self, ga, subgraph, root):
|
||||
"""Finds topology for unrooted subgraph
|
||||
@ -204,7 +201,7 @@ class TopologyApis(EntityGraphApisBase):
|
||||
ga.connected_component_subgraphs(subgraph)
|
||||
|
||||
for component_subgraph in local_connected_component_subgraphs:
|
||||
entities += component_subgraph.nodes()
|
||||
entities += list(component_subgraph.nodes())
|
||||
instance_in_component_subgraph = \
|
||||
self._find_instance_in_graph(component_subgraph)
|
||||
if instance_in_component_subgraph:
|
||||
@ -227,7 +224,7 @@ class TopologyApis(EntityGraphApisBase):
|
||||
|
||||
@staticmethod
|
||||
def _find_instance_in_graph(graph):
|
||||
for node, node_data in graph.nodes_iter(data=True):
|
||||
for node, node_data in graph.nodes(data=True):
|
||||
if node_data[VProps.VITRAGE_CATEGORY] == \
|
||||
EntityCategory.RESOURCE \
|
||||
and node_data[VProps.VITRAGE_TYPE] == \
|
||||
|
@ -90,11 +90,11 @@ class NXAlgorithm(GraphAlgorithm):
|
||||
edges=self._edge_result_to_list(e_result))
|
||||
|
||||
LOG.debug('graph_query_vertices: find graph: nodes %s, edges %s',
|
||||
str(graph._g.nodes(data=True)),
|
||||
str(graph._g.edges(data=True)))
|
||||
str(list(graph._g.nodes(data=True))),
|
||||
str(list(graph._g.edges(data=True))))
|
||||
LOG.debug('graph_query_vertices: real graph: nodes %s, edges %s',
|
||||
str(self.graph._g.nodes(data=True)),
|
||||
str(self.graph._g.edges(data=True)))
|
||||
str(list(self.graph._g.nodes(data=True))),
|
||||
str(list(self.graph._g.edges(data=True))))
|
||||
return graph
|
||||
|
||||
def sub_graph_matching(self,
|
||||
@ -148,18 +148,18 @@ class NXAlgorithm(GraphAlgorithm):
|
||||
vertices_ids = [vertex.vertex_id for vertex in vertices]
|
||||
|
||||
graph = self._create_new_graph('graph')
|
||||
graph._g = self.graph._g.subgraph(vertices_ids)
|
||||
graph._g = self.graph._g.subgraph(vertices_ids).copy()
|
||||
|
||||
# delete non matching edges
|
||||
if edge_attr_filter:
|
||||
self._apply_edge_attr_filter(graph, edge_attr_filter)
|
||||
|
||||
LOG.debug('match query, find graph: nodes %s, edges %s',
|
||||
str(graph._g.nodes(data=True)),
|
||||
str(graph._g.edges(data=True)))
|
||||
str(list(graph._g.nodes(data=True))),
|
||||
str(list(graph._g.edges(data=True))))
|
||||
LOG.debug('match query, real graph: nodes %s, edges %s',
|
||||
str(self.graph._g.nodes(data=True)),
|
||||
str(self.graph._g.edges(data=True)))
|
||||
str(list(self.graph._g.nodes(data=True))),
|
||||
str(list(self.graph._g.edges(data=True))))
|
||||
|
||||
return graph
|
||||
|
||||
@ -230,8 +230,8 @@ class NXAlgorithm(GraphAlgorithm):
|
||||
|
||||
@staticmethod
|
||||
def _apply_edge_attr_filter(graph, edge_attr_filter):
|
||||
edges_iter = graph._g.edges_iter(data=True, keys=True)
|
||||
edges_to_remove = [(u, v, k) for (u, v, k, d) in edges_iter
|
||||
edges = graph._g.edges(data=True, keys=True)
|
||||
edges_to_remove = [(u, v, k) for (u, v, k, d) in edges
|
||||
if not check_filter(d, edge_attr_filter)]
|
||||
for source, target, key in edges_to_remove:
|
||||
graph._g.remove_edge(u=source, v=target, key=key)
|
||||
|
@ -64,9 +64,9 @@ class NXGraph(Graph):
|
||||
|
||||
def copy(self):
|
||||
# Networkx graph copy is very slow, so we implement
|
||||
nodes = self._g.nodes_iter(data=True)
|
||||
nodes = self._g.nodes(data=True)
|
||||
vertices = [Vertex(vertex_id=n, properties=data) for n, data in nodes]
|
||||
edges_iter = self._g.edges_iter(data=True, keys=True)
|
||||
edges_iter = self._g.edges(data=True, keys=True)
|
||||
edges = [Edge(source_id=u, target_id=v, label=l, properties=data)
|
||||
for u, v, l, data in edges_iter]
|
||||
return NXGraph(self.name, vertices, edges)
|
||||
@ -82,7 +82,10 @@ class NXGraph(Graph):
|
||||
|
||||
def _add_vertex(self, v):
|
||||
properties_copy = copy.copy(v.properties)
|
||||
self._g.add_node(n=v.vertex_id, attr_dict=properties_copy)
|
||||
if properties_copy:
|
||||
self._g.add_node(n=v.vertex_id, **properties_copy)
|
||||
else:
|
||||
self._g.add_node(n=v.vertex_id)
|
||||
|
||||
@Notifier.update_notify
|
||||
def add_edge(self, e):
|
||||
@ -95,8 +98,12 @@ class NXGraph(Graph):
|
||||
|
||||
def _add_edge(self, e):
|
||||
properties_copy = copy.copy(e.properties)
|
||||
self._g.add_edge(u=e.source_id, v=e.target_id,
|
||||
key=e.label, attr_dict=properties_copy)
|
||||
if properties_copy:
|
||||
self._g.add_edge(u=e.source_id, v=e.target_id,
|
||||
key=e.label, **properties_copy)
|
||||
else:
|
||||
self._g.add_edge(u=e.source_id, v=e.target_id,
|
||||
key=e.label)
|
||||
|
||||
def get_vertex(self, v_id):
|
||||
"""Fetch a vertex from the graph
|
||||
@ -175,8 +182,10 @@ class NXGraph(Graph):
|
||||
if not orig_prop:
|
||||
self._add_vertex(v)
|
||||
return
|
||||
new_prop = self._merge_properties(orig_prop, v.properties)
|
||||
self._g.node[v.vertex_id] = new_prop
|
||||
self._g.node[v.vertex_id].update(v.properties)
|
||||
for prop, value in v.properties.items():
|
||||
if value is None:
|
||||
del self._g.node[v.vertex_id][prop]
|
||||
|
||||
@Notifier.update_notify
|
||||
def update_edge(self, e):
|
||||
@ -184,15 +193,17 @@ class NXGraph(Graph):
|
||||
|
||||
:type e: Edge
|
||||
"""
|
||||
orig_prop = self._g.edge.get(
|
||||
orig_prop = self._g.adj.get(
|
||||
e.source_id, {}).get(
|
||||
e.target_id, {}).get(
|
||||
e.label, None)
|
||||
if not orig_prop:
|
||||
self._add_edge(e)
|
||||
return
|
||||
new_prop = self._merge_properties(orig_prop, e.properties)
|
||||
self._g.edge[e.source_id][e.target_id][e.label] = new_prop
|
||||
self._g.adj[e.source_id][e.target_id][e.label].update(e.properties)
|
||||
for prop, value in e.properties.items():
|
||||
if value is None:
|
||||
del self._g.adj[e.source_id][e.target_id][e.label][prop]
|
||||
|
||||
def remove_vertex(self, v):
|
||||
"""Remove Vertex v and its edges from the graph
|
||||
@ -216,12 +227,12 @@ class NXGraph(Graph):
|
||||
return check_filter(vertex_data[1], vertex_attr_filter)
|
||||
|
||||
if not query_dict:
|
||||
items = filter(check_vertex, self._g.nodes_iter(data=True))
|
||||
items = filter(check_vertex, list(self._g.nodes(data=True)))
|
||||
return [vertex_copy(node, node_data) for node, node_data in items]
|
||||
elif not vertex_attr_filter:
|
||||
vertices = []
|
||||
match_func = create_predicate(query_dict)
|
||||
for node, node_data in self._g.nodes_iter(data=True):
|
||||
for node, node_data in self._g.nodes(data=True):
|
||||
v = vertex_copy(node, node_data)
|
||||
if match_func(v):
|
||||
vertices.append(v)
|
||||
@ -283,14 +294,34 @@ class NXGraph(Graph):
|
||||
return nodes, edges_filtered2
|
||||
|
||||
def json_output_graph(self, **kwargs):
|
||||
"""supports both 1.10<=networkx<2.0 and networx>=2.0 by returning the
|
||||
|
||||
same json output regardless networx version
|
||||
|
||||
:return: graph in json format
|
||||
"""
|
||||
|
||||
# TODO(annarez): when we decide to support networkx 2.0 with
|
||||
# versioning of Vitrage, we can move part of the logic to vitrageclient
|
||||
node_link_data = json_graph.node_link_data(self._g)
|
||||
node_link_data.update(kwargs)
|
||||
|
||||
vitrage_id_to_index = dict()
|
||||
|
||||
for index, node in enumerate(node_link_data['nodes']):
|
||||
vitrage_id_to_index[node[VProps.VITRAGE_ID]] = index
|
||||
if VProps.ID in self._g.node[node[VProps.ID]]:
|
||||
node[VProps.ID] = self._g.node[node[VProps.ID]][VProps.ID]
|
||||
node[VProps.GRAPH_INDEX] = index
|
||||
|
||||
vers = nx.__version__
|
||||
if vers >= '2.0':
|
||||
for i in range(len(node_link_data['links'])):
|
||||
node_link_data['links'][i]['source'] = vitrage_id_to_index[
|
||||
node_link_data['links'][i]['source']]
|
||||
node_link_data['links'][i]['target'] = vitrage_id_to_index[
|
||||
node_link_data['links'][i]['target']]
|
||||
|
||||
return json.dumps(node_link_data)
|
||||
|
||||
def to_json(self):
|
||||
|
@ -72,9 +72,9 @@ class BaseTest(base.BaseTestCase):
|
||||
edges of each graph.
|
||||
"""
|
||||
g1_nodes = g1._g.node
|
||||
g1_edges = g1._g.edge
|
||||
g1_edges = g1._g.adj
|
||||
g2_nodes = g2._g.node
|
||||
g2_edges = g2._g.edge
|
||||
g2_edges = g2._g.adj
|
||||
self.assertEqual(g1.num_vertices(), g2.num_vertices(),
|
||||
"Two graphs have different amount of nodes")
|
||||
self.assertEqual(g1.num_edges(), g2.num_edges(),
|
||||
@ -83,9 +83,10 @@ class BaseTest(base.BaseTestCase):
|
||||
self.assert_dict_equal(g1_nodes.get(n_id),
|
||||
g2_nodes.get(n_id),
|
||||
"Nodes of each graph are not equal")
|
||||
|
||||
for e_source_id in g1_edges:
|
||||
self.assert_dict_equal(g1_edges.get(e_source_id),
|
||||
g2_edges.get(e_source_id),
|
||||
self.assert_dict_equal(dict(g1_edges.get(e_source_id)),
|
||||
dict(g2_edges.get(e_source_id)),
|
||||
"Edges of each graph are not equal")
|
||||
|
||||
@staticmethod
|
||||
|
Loading…
x
Reference in New Issue
Block a user