class KamiGraph: """Graph container data structure. Attributes ---------- graph : nx.(Di)Graph Graph meta_typing : dict Typing of the graph by the meta-model reference_typing : dict Typing of the graph by the reference graph """ def __init__(self, graph=None, meta_typing=None, reference_typing=None): """Initialize graph container.""" if graph: self.graph = NXGraph.copy(graph) else: self.graph = NXGraph() if meta_typing: self.meta_typing = copy.deepcopy(meta_typing) else: self.meta_typing = dict() if reference_typing: self.reference_typing = copy.deepcopy(reference_typing) else: self.reference_typing = dict() return def add_node(self, node_id, attrs=None, meta_typing=None, reference_typing=None): """Add node + typings to a nugget.""" self.graph.add_node(node_id, attrs) if meta_typing: self.meta_typing[node_id] = meta_typing if reference_typing: self.reference_typing[node_id] = reference_typing return def add_node_attrs(self, node_id, attrs): self.graph.add_node_attrs(node_id, attrs) def add_edge(self, s, t, attrs=None): """Add edge between the nodes of a nugget.""" self.graph.add_edge(s, t, attrs) return def remove_node(self, node_id): self.graph.remove_node(node_id) del self.meta_typing[node_id] if node_id in self.reference_typing: del self.reference_typing[node_id] def remove_node_attrs(self, node_id, attrs): self.graph.remove_node_attrs(node_id, attrs) def remove_edge(self, s, t): self.graph.remove_edge(s, t) def nodes(self): """Return a list of nodes of the nugget graph.""" return self.graph.nodes() def edges(self): """Return a list of edges of the nugget graph.""" return self.graph.edges()
class TestGraphClasses: """Main test class.""" def __init__(self): """Initialize test object.""" self.nx_graph = NXGraph() try: self.neo4j_graph = Neo4jGraph(uri="bolt://localhost:7687", user="******", password="******") self.neo4j_graph._clear() except: warnings.warn("Neo4j is down, skipping Neo4j-related tests") self.neo4j_graph = None node_list = [("b", { "name": "Bob", "age": 20 }), ("a", { "name": "Alice", "age": 35 }), ("d", { "name": "dummy" })] edge_list = [("a", "b", { "type": "friends", "since": 1999 }), ("d", "a"), ("b", "d")] self.nx_graph.add_nodes_from(node_list) self.nx_graph.add_edges_from(edge_list) if self.neo4j_graph: self.neo4j_graph.add_nodes_from(node_list) self.neo4j_graph.add_edges_from(edge_list) node = "c" attrs = {"name": "Claire", "age": 66} self.nx_graph.add_node(node, attrs) if self.neo4j_graph: self.neo4j_graph.add_node(node, attrs) edge_attrs = {"type": "parent"} self.nx_graph.add_edge("c", "b", edge_attrs) if self.neo4j_graph: self.neo4j_graph.add_edge("c", "b", edge_attrs) self.nx_graph.remove_edge("d", "a") if self.neo4j_graph: self.neo4j_graph.remove_edge("d", "a") self.nx_graph.remove_node("d") if self.neo4j_graph: self.neo4j_graph.remove_node("d") self.nx_graph.update_node_attrs("a", {"name": "Alison"}) if self.neo4j_graph: self.neo4j_graph.update_node_attrs("a", {"name": "Alison"}) self.nx_graph.update_edge_attrs("a", "b", {"type": "enemies"}) if self.neo4j_graph: self.neo4j_graph.update_edge_attrs("a", "b", {"type": "enemies"}) self.nx_graph.set_node_attrs("a", {"age": 19}, update=False) if self.neo4j_graph: self.neo4j_graph.set_node_attrs("a", {"age": 19}, update=False) self.nx_graph.set_edge_attrs("a", "b", {"since": 1945}, update=False) if self.neo4j_graph: self.neo4j_graph.set_edge_attrs("a", "b", {"since": 1945}, update=False) self.nx_graph.add_node_attrs("a", {"gender": {"M", "F"}}) if self.neo4j_graph: self.neo4j_graph.add_node_attrs("a", {"gender": {"M", "F"}}) self.nx_graph.add_edge_attrs("a", "b", {"probability": 0.5}) if self.neo4j_graph: self.neo4j_graph.add_edge_attrs("a", "b", {"probability": 0.5}) self.nx_graph.remove_node_attrs("a", {"gender": "F"}) if self.neo4j_graph: self.neo4j_graph.remove_node_attrs("a", {"gender": "F"}) self.nx_graph.remove_edge_attrs("a", "b", {"probability": 0.5}) if self.neo4j_graph: self.neo4j_graph.remove_edge_attrs("a", "b", {"probability": 0.5}) clone_id = self.nx_graph.clone_node("b", "b_clone") if self.neo4j_graph: self.neo4j_graph.clone_node("b", "b_clone") # Test relabeling self.nx_graph.relabel_node("b", "baba") if self.neo4j_graph: self.neo4j_graph.relabel_node("b", "baba") self.nx_graph.relabel_node("baba", "b") if self.neo4j_graph: self.neo4j_graph.relabel_node("baba", "b") self.nx_graph.relabel_nodes({ clone_id: "lala", "b": "b1", "a": "a1", "c": "c1" }) if self.neo4j_graph: self.neo4j_graph.relabel_nodes({ clone_id: "lala", "b": "b1", "a": "a1", "c": "c1" }) self.nx_graph.relabel_nodes({ "b1": "b", "a1": "a", "c1": "c", "lala": clone_id }) if self.neo4j_graph: self.neo4j_graph.relabel_nodes({ "b1": "b", "a1": "a", "c1": "c", "lala": clone_id }) self.nx_graph.merge_nodes(["b", "c"]) if self.neo4j_graph: self.neo4j_graph.merge_nodes(["b", "c"]) self.nx_graph.copy_node("a", "a_copy") if self.neo4j_graph: self.neo4j_graph.copy_node("a", "a_copy") # Test find matching pattern = NXGraph() pattern.add_nodes_from(["x", ("y", {"name": "Claire"}), "z"]) pattern.add_edges_from([("x", "y"), ("y", "y"), ("y", "z")]) instances1 = self.nx_graph.find_matching(pattern) if self.neo4j_graph: instances2 = self.neo4j_graph.find_matching(pattern) assert (instances1 == instances2) rule = Rule.from_transform(pattern) p_n, r_n = rule.inject_clone_node("y") rule.inject_remove_edge(p_n, "y") rule.inject_remove_edge("y", "y") rule.inject_add_node("w", {"name": "Frank"}) rule.inject_add_edge("w", r_n, {"type": "parent"}) rhs_g1 = self.nx_graph.rewrite(rule, instances1[0]) if self.neo4j_graph: rhs_g2 = self.neo4j_graph.rewrite(rule, instances1[0]) self.nx_graph.relabel_node(rhs_g1[r_n], "b") if self.neo4j_graph: self.neo4j_graph.relabel_node(rhs_g2[r_n], "b") self.nx_graph.relabel_node(rhs_g1["y"], "c") if self.neo4j_graph: self.neo4j_graph.relabel_node(rhs_g2["y"], "c") # Test the two obtained graphs are the same assert (self.nx_graph == self.neo4j_graph) assert (set(self.nx_graph.predecessors("b")) == set( self.neo4j_graph.predecessors("b"))) assert (set(self.nx_graph.successors("a")) == set( self.neo4j_graph.successors("a"))) assert ( self.nx_graph.get_node("c") == self.neo4j_graph.get_node("c")) assert (self.nx_graph.get_edge("c", "b") == self.neo4j_graph.get_edge( "c", "b")) def test_getters(self): """Test various getters.""" if self.neo4j_graph: assert (set(self.nx_graph.nodes()) == set( self.neo4j_graph.nodes())) assert (set(self.nx_graph.edges()) == set( self.neo4j_graph.edges())) self.neo4j_graph.nodes(data=True) self.neo4j_graph.edges(data=True) assert ( self.nx_graph.get_node("a") == self.neo4j_graph.get_node("a")) assert (self.nx_graph.get_edge("a", "b") == self.neo4j_graph.get_edge( "a", "b")) assert (set(self.nx_graph.in_edges("b")) == set( self.neo4j_graph.in_edges("b"))) assert (set(self.nx_graph.out_edges("a")) == set( self.neo4j_graph.out_edges("a"))) def test_load_export(self): self.nx_graph.export("nxgraph.json") if self.neo4j_graph: self.neo4j_graph.export("neo4jgraph.json") g1 = NXGraph.load("nxgraph.json") if self.neo4j_graph: p = Neo4jGraph(driver=self.neo4j_graph._driver, node_label="new_node", edge_label="new_edge") p._clear() g2 = Neo4jGraph.load(driver=self.neo4j_graph._driver, filename="neo4jgraph.json", node_label="new_node", edge_label="new_edge") assert (g1 == g2)