def test_add_qnode_bad_parameters(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' bad_parameters_list = [ { 'parameters': ['ids', 'PICKLES:123'], 'error_code': 'ParametersNotDict' }, { 'parameters': { 'pickles': 'on the side' }, 'error_code': 'UnknownParameter' }, { 'parameters': { 'ids': 'n2', 'category': 'biolink:Disease' }, 'error_code': 'UnknownParameter' }, ] template_response = copy.deepcopy(response) for bad_parameters in bad_parameters_list: response = copy.deepcopy(template_response) message = response.envelope.message print(bad_parameters) messenger.add_qnode(response, bad_parameters['parameters']) assert response.status == 'ERROR' assert len(message.query_graph.nodes) == 0 assert response.error_code == bad_parameters['error_code']
def test_add_qedge_duplicate_key(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response, { 'key': 'n00', 'ids': ['CHEMBL.COMPOUND:CHEMBL112'] }) messenger.add_qnode(response, { 'key': 'n01', 'categories': ['biolink:Protein'] }) messenger.add_qedge(response, { 'key': 'e00', 'subject': 'n00', 'object': 'n01' }) assert response.status == 'OK' messenger.add_qedge( response, { 'key': 'e00', 'subject': 'n00', 'object': 'n01', 'predicates': ['biolink:treats'] }) print( json.dumps(ast.literal_eval(repr(message.query_graph.edges)), sort_keys=True, indent=2)) assert response.status == 'ERROR' assert isinstance(message.query_graph.nodes, dict) assert len(message.query_graph.edges) == 1 assert response.error_code == 'QEdgeDuplicateKey'
def QGI_test5(): # This is to test forked/non-linear queries (currently not working properly) input_query_graph = { "message": { "query_graph": { "nodes": { "n0": { "categories": ["biolink:Gene"] }, "n1": { "ids": ["CHEBI:45783"], "categories": ["biolink:ChemicalEntity"] }, "n2": { "ids": ["MONDO:0005301"], "categories": ["biolink:Disease"] }, "n3": { "categories": ["biolink:ChemicalEntity"] } }, "edges": { "e01": { "subject": "n0", "object": "n1", "predicates": ["biolink:related_to"] }, "e02": { "subject": "n0", "object": "n2", "predicates": ["biolink:related_to"] }, "e03": { "subject": "n0", "object": "n3", "predicates": ["biolink:related_to"] } } } } } #### Create a template Message response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) message = ARAXMessenger().from_dict(input_query_graph['message']) response.envelope.message.query_graph = message.query_graph interpreter = ARAXQueryGraphInterpreter() interpreter.translate_to_araxi(response) if response.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response araxi_commands = response.data['araxi_commands'] for cmd in araxi_commands: print(f" - {cmd}")
def test_create_message_basic(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message assert response.envelope.type == 'translator_reasoner_response' assert response.envelope.schema_version == '1.0.0'
def test_create_message_node_edge_types(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message assert isinstance(message.knowledge_graph.nodes, dict) assert isinstance(message.knowledge_graph.edges, dict) assert isinstance(message.query_graph.nodes, dict) assert isinstance(message.query_graph.edges, dict)
def test_example1(): query_graph = { "edges": { "e00": { "subject": "n00", "object": "n01" }, "e01": { "subject": "n00", "object": "n01", "predicate": "biolink:contraindicated_for", "exclude": True } }, "nodes": { "n00": { "id": "MONDO:0001627", "category": "biolink:Disease" }, "n01": { "category": "biolink:ChemicalSubstance" } } } from ARAX_messenger import ARAXMessenger response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) response.envelope.message.query_graph = QueryGraph().from_dict(query_graph) query_graph_info = QueryGraphInfo() result = query_graph_info.assess(response.envelope.message) response.merge(result) if result.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response query_graph_info_dict = { 'n_nodes': query_graph_info.n_nodes, 'n_edges': query_graph_info.n_edges, 'is_bifurcated_graph': query_graph_info.is_bifurcated_graph, 'start_node': query_graph_info.start_node, 'node_info': query_graph_info.node_info, 'edge_info': query_graph_info.edge_info, 'node_order': query_graph_info.node_order, 'edge_order': query_graph_info.edge_order, 'node_category_map': query_graph_info.node_category_map, 'edge_predicate_map': query_graph_info.edge_predicate_map, } print( json.dumps(ast.literal_eval(repr(query_graph_info_dict)), sort_keys=True, indent=2))
def test_add_qnode_bad_name(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response,{ 'name': 'Big Bird' }) assert response.status == 'ERROR' assert isinstance(message.query_graph.nodes, dict) assert len(message.query_graph.nodes) == 0 assert response.error_code == 'UnresolvableNodeName'
def test_add_qnode_name(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response,{ 'name': 'acetaminophen' }) assert response.status == 'OK' assert isinstance(message.query_graph.nodes, dict) assert len(message.query_graph.nodes) == 1 assert message.query_graph.nodes['n00'].id == 'CHEMBL.COMPOUND:CHEMBL112'
def test_add_qnode_type(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response,{ 'category': 'biolink:Protein' }) assert response.status == 'OK' assert isinstance(message.query_graph.nodes, dict) assert len(message.query_graph.nodes) == 1 assert message.query_graph.nodes['n00'].category == 'biolink:Protein'
def test_add_qnode_basic(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response,{}) assert response.status == 'OK' assert isinstance(message.query_graph.nodes, dict) assert len(message.query_graph.nodes) == 1 assert message.query_graph.nodes['n00'].id == None
def test_add_qnode_curie_list(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response,{ 'id': ['UniProtKB:P14136','UniProtKB:P35579'] }) assert response.status == 'OK' assert isinstance(message.query_graph.nodes, dict) assert len(message.query_graph.nodes) == 1 assert len(message.query_graph.nodes['n00'].id) == 2
def test_add_qnode_group_id_is_set_false(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response,{ 'category': 'biolink:Protein', 'is_set' : 'false', 'option_group_id' : '0' }) assert response.status == 'ERROR' assert isinstance(message.query_graph.nodes, dict) assert len(message.query_graph.nodes) == 0 assert response.error_code == 'InputMismatch'
def QGI_test3(): input_query_graph = { "message": { "query_graph": { "nodes": { "n00": { "id": "MONDO:0002715" }, "n01": { "category": "biolink:ChemicalSubstance" }, "n02": { "category": "biolink:Gene" } }, "edges": { "e00": { "predicate": "biolink:correlated_with", "subject": "n00", "object": "n01" }, "e01": { "predicate": "biolink:related_to", "subject": "n01", "object": "n02" } } } } } #### Create a template Message response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) message = ARAXMessenger().from_dict(input_query_graph['message']) response.envelope.message.query_graph = message.query_graph interpreter = ARAXQueryGraphInterpreter() interpreter.translate_to_araxi(response) if response.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response araxi_commands = response.data['araxi_commands'] for cmd in araxi_commands: print(f" - {cmd}") #### Show the final result print('-------------------------') print(response.show(level=ARAXResponse.DEBUG)) print(json.dumps(message.to_dict(), sort_keys=True, indent=2))
def QGI_test1(): #### Some qnode examples test_query_graphs = [ [ { 'id': 'n10', 'curie': 'DOID:9281', 'category': 'disease'}, { 'id': 'n11', 'category': 'chemical_substance'}, { 'id': 'e10', 'source_id': 'n10', 'target_id': 'n11', 'category': 'treats'} ], [ { 'id': 'n10', 'curie': 'DOID:9281'}, { 'id': 'n11', 'category': 'protein'}, { 'id': 'e10', 'source_id': 'n10', 'target_id': 'n11'} ], [ { 'id': 'n10', 'curie': 'DOID:9281'}, { 'id': 'n11', 'category': 'protein'}, { 'id': 'n12', 'category': 'chemical_substance'}, { 'id': 'e10', 'source_id': 'n10', 'target_id': 'n11'}, { 'id': 'e11', 'source_id': 'n11', 'target_id': 'n12'} ], [ { 'id': 'n10', 'curie': 'DOID:9281'}, { 'id': 'n11', 'category': 'chemical_substance'}, { 'id': 'e10', 'source_id': 'n10', 'target_id': 'n11'} ], [ { 'id': 'n10', 'curie': 'DOID:9281', 'category': 'disease'}, { 'id': 'n11', 'category': 'chemical_substance'}, { 'id': 'e10', 'source_id': 'n10', 'target_id': 'n11'} ], ] #interpreter = ARAXQueryGraphInterpreter() #print(json.dumps(interpreter.query_graph_tree,sort_keys=True,indent=2)) #return for test_query_graph in test_query_graphs: #### Create a response object for each test response = ARAXResponse() #### Create a template Message messenger = ARAXMessenger() messenger.create_envelope(response) message = response.envelope.message for parameters in test_query_graph: if 'n' in parameters['id']: messenger.add_qnode(response, parameters) if response.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response elif 'e' in parameters['id']: #print(f"++ Adding qedge with {parameters}") messenger.add_qedge(response, parameters) if response.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response else: response.error(f"Unrecognized component {parameters['id']}") return response interpreter = ARAXQueryGraphInterpreter() interpreter.translate_to_araxi(response) if response.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response araxi_commands = response.data['araxi_commands'] for cmd in araxi_commands: print(f" - {cmd}")
def QGI_test4(): input_query_graph = { "message": { "query_graph": { "nodes": { "n00": { "categories": [ "biolink:Gene" ], "is_set": False }, "n01": { "ids": [ "MONDO:0018177" ], "categories": [ "biolink:Disease" ], "is_set": False } }, "edges": { "e00": { "subject": "n00", "object": "n01", "exclude": False } } } } } #### Create a template Message response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) message = ARAXMessenger().from_dict(input_query_graph['message']) response.envelope.message.query_graph = message.query_graph interpreter = ARAXQueryGraphInterpreter() interpreter.translate_to_araxi(response) if response.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response araxi_commands = response.data['araxi_commands'] for cmd in araxi_commands: print(f" - {cmd}")
def test_add_qnode_bad_parameters(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' bad_parameters_list = [ { 'parameters': [ 'id', 'PICKLES:123' ], 'error_code': 'ParametersNotDict' }, { 'parameters': { 'id': 'UniProtKB:P14136', 'is_set': 'true' }, 'error_code': 'IdScalarButIsSetTrue' }, { 'parameters': { 'pickles': 'on the side' }, 'error_code': 'UnknownParameter' }, ] template_response = copy.deepcopy(response) for bad_parameters in bad_parameters_list: response = copy.deepcopy(template_response) message = response.envelope.message print(bad_parameters) messenger.add_qnode(response, bad_parameters['parameters']) assert response.status == 'ERROR' assert len(message.query_graph.nodes) == 0 assert response.error_code == bad_parameters['error_code']
def test_add_qnode_duplicate_key(): response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response, { 'key': 'n00', 'ids': ['CHEMBL.COMPOUND:CHEMBL112'] }) assert response.status == 'OK' messenger.add_qnode(response, {'key': 'n00', 'ids': ['CHEBI:46195']}) print( json.dumps(ast.literal_eval(repr(message.query_graph.nodes)), sort_keys=True, indent=2)) assert response.status == 'ERROR' assert isinstance(message.query_graph.nodes, dict) assert len(message.query_graph.nodes) == 1 assert response.error_code == 'QNodeDuplicateKey'
def test_add_qedge_multitest(): # Set up a message with two nodes response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) assert response.status == 'OK' message = response.envelope.message messenger.add_qnode(response,{ 'name': 'acetaminophen' }) assert response.status == 'OK' messenger.add_qnode(response,{ 'category': 'biolink:Protein' }) assert response.status == 'OK' # Set up a list of parameters to feed to add_qedge() and what the result should be parameters_list = [ { 'status': 'ERROR', 'parameters': [ 'subject', 'n00' ], 'error_code': 'ParametersNotDict' }, { 'status': 'OK', 'parameters': { 'subject': 'n00', 'object': 'n01' }, 'error_code': 'OK' }, { 'status': 'OK', 'parameters': { 'subject': 'n00', 'object': 'n01', 'key': 'e99' }, 'error_code': 'OK' }, { 'status': 'OK', 'parameters': { 'subject': 'n00', 'object': 'n01', 'key': 'e99', 'predicate': 'physically_interacts_with' }, 'error_code': 'OK' }, { 'status': 'ERROR', 'parameters': { 'subject': 'n00' }, 'error_code': 'MissingTargetKey' }, { 'status': 'ERROR', 'parameters': { 'object': 'n00' }, 'error_code': 'MissingSourceKey' }, { 'status': 'ERROR', 'parameters': { 'subject': 'n99', 'object': 'n01' }, 'error_code': 'UnknownSourceKey' }, { 'status': 'ERROR', 'parameters': { 'subject': 'n00', 'object': 'n99' }, 'error_code': 'UnknownTargetKey' }, { 'status': 'ERROR', 'parameters': { 'pickles': 'on the side' }, 'error_code': 'UnknownParameter' }, ] # Loop over all the parameter sets and try to run it template_response = copy.deepcopy(response) for parameters in parameters_list: response = copy.deepcopy(template_response) message = response.envelope.message print(parameters) messenger.add_qedge(response, parameters['parameters']) assert response.status == parameters['status'] if parameters['status'] == 'OK': assert len(message.query_graph.edges) == 1 continue assert len(message.query_graph.edges) == 0 assert response.error_code == parameters['error_code']
def QGI_test2(): #### Set example query_graph # TRAPI 0.9.2 input_query_graph = { "message": { "query_graph": { "nodes": [ { "id": "n1", "category": "chemical_substance" }, { "id": "n2", "curie": "UMLS:C0002395" } ], "edges": [ { "id": "e1", "predicate": "clinically_tested_approved_unknown_phase", "source_id": "n1", "target_id": "n2" } ] } } } # TRAPI 1.0.0 input_query_graph = { "message": { "query_graph": { "nodes": { "n1": { "category": "biolink:ChemicalEntity" }, "n2": { "id": "UMLS:C0002395" } }, "edges": { "e1": { "predicate": "clinically_tested_approved_unknown_phase", "subject": "n1", "object": "n2" } } } } } # TRAPI 1.1.0 input_query_graph = { "message": { "query_graph": { "nodes": { "n1": { "categories": [ "biolink:ChemicalEntity" ] }, "n2": { "ids": [ "UMLS:C0002395" ] } }, "edges": { "e1": { "predicates": [ "biolink:clinically_tested_approved_unknown_phase" ], "subject": "n1", "object": "n2" } } } } } #### Create a template Message response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) message = ARAXMessenger().from_dict(input_query_graph['message']) response.envelope.message.query_graph = message.query_graph interpreter = ARAXQueryGraphInterpreter() interpreter.translate_to_araxi(response) if response.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response araxi_commands = response.data['araxi_commands'] for cmd in araxi_commands: print(f" - {cmd}") #### Show the final result print('-------------------------') print(response.show(level=ARAXResponse.DEBUG)) print(json.dumps(message.to_dict(),sort_keys=True,indent=2))
def test_example1(): test_query_graphs = [ { "description": "Two nodes, one edge linking them, 1 CURIE", "nodes": { "n00": { "ids": ["MONDO:0001627"] }, "n01": { "categories": ["biolink:ChemicalEntity"] } }, "edges": { "e00": { "subject": "n00", "object": "n01", "predicates": ["biolink:physically_interacts_with"] } } }, { "description": "Two nodes, two edges linking them, 1 CURIE, one of which is excluded", "nodes": { "n00": { "ids": ["MONDO:0001627"] }, "n01": { "categories": ["biolink:ChemicalEntity"] } }, "edges": { "e00": { "subject": "n00", "object": "n01" }, "e01": { "subject": "n00", "object": "n01", "predicates": ["biolink:contraindicated_for"], "exclude": True } } }, { "description": "Two nodes, one edge linking them, both nodes are CURIEs", "nodes": { "n00": { "ids": ["MONDO:0001627"] }, "n01": { "ids": ["CHEMBL.COMPOUND:CHEMBL112"] } }, "edges": { "e00": { "subject": "n00", "object": "n01" } } }, { "description": "Three nodes, 2 edges, 1 CURIE, simple linear chain", "nodes": { "n00": { "ids": ["MONDO:0001627"] }, "n01": { "categories": ["biolink:ChemicalEntity"] }, "n02": { "categories": ["biolink:Protein"] } }, "edges": { "e00": { "subject": "n00", "object": "n01", "predicates": ["biolink:physically_interacts_with"] }, "e01": { "subject": "n01", "object": "n02" } } }, { "description": "Three nodes, 2 edges, but the CURIE is in the middle. What does that even mean?", "nodes": { "n00": { "categories": ["biolink:ChemicalEntity"] }, "n01": { "ids": ["MONDO:0001627"] }, "n02": { "categories": ["biolink:Protein"] } }, "edges": { "e00": { "subject": "n00", "object": "n01", "predicates": ["biolink:physically_interacts_with"] }, "e01": { "subject": "n01", "object": "n02" } } }, { "description": "Four nodes, 3 edges, 1 CURIE, simple linear chain", "nodes": { "n00": { "ids": ["MONDO:0001627"] }, "n01": { "categories": ["biolink:ChemicalEntity"] }, "n02": { "categories": ["biolink:Protein"] }, "n03": { "categories": ["biolink:Disease"] } }, "edges": { "e00": { "subject": "n00", "object": "n01", "predicates": ["biolink:physically_interacts_with"] }, "e01": { "subject": "n01", "object": "n02" }, "e02": { "subject": "n02", "object": "n03" } } }, { "description": "Two nodes, one edge linking them, 0 CURIEs", "nodes": { "n00": { "categories": ["biolink:Drug"] }, "n01": { "categories": ["biolink:ChemicalEntity"] } }, "edges": { "e00": { "subject": "n00", "object": "n01", "predicates": ["biolink:physically_interacts_with"] } } }, { "description": "One node only", "nodes": { "n00": { "ids": ["MONDO:0001627"] } }, "edges": {} }, ] from ARAX_messenger import ARAXMessenger for test_query_graph in test_query_graphs: response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) print( '==================================================================' ) description = test_query_graph['description'] del test_query_graph['description'] print(f"Query Graph '{description}'") response.envelope.message.query_graph = QueryGraph().from_dict( test_query_graph) query_graph_info = QueryGraphInfo() result = query_graph_info.assess(response.envelope.message) response.merge(result) if result.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response query_graph_info_dict = { 'n_nodes': query_graph_info.n_nodes, 'n_edges': query_graph_info.n_edges, 'is_bifurcated_graph': query_graph_info.is_bifurcated_graph, 'start_node': query_graph_info.start_node['key'], 'simple_query_graph_template': query_graph_info.query_graph_templates['simple'], #'start_node': query_graph_info.start_node, #'node_info': query_graph_info.node_info, #'edge_info': query_graph_info.edge_info, #'node_order': query_graph_info.node_order, #'edge_order': query_graph_info.edge_order, #'node_category_map': query_graph_info.node_category_map, #'edge_predicate_map': query_graph_info.edge_predicate_map, } print( json.dumps(ast.literal_eval(repr(query_graph_info_dict)), sort_keys=True, indent=2))
def QGI_test7(): # This is to test a three hop query with one end pinned (should result in FET ARAXi commands), and actually run the query input_query_graph = { "message": { "query_graph": { "edges": { "e00": { "object": "n01", "subject": "n00" }, "e01": { "object": "n02", "subject": "n01" }, "e02": { "object": "n03", "subject": "n02" } }, "nodes": { "n00": { "categories": [ "biolink:ChemicalEntity" ], "ids": [ "DRUGBANK:DB00150" ] }, "n01": { "categories": [ "biolink:Protein" ] }, "n02": { "categories": [ "biolink:MolecularActivity" ] }, "n03": { "categories": [ "biolink:ChemicalEntity" ] } } } } } #### Create a template Message response = ARAXResponse() messenger = ARAXMessenger() messenger.create_envelope(response) message = ARAXMessenger().from_dict(input_query_graph['message']) response.envelope.message.query_graph = message.query_graph interpreter = ARAXQueryGraphInterpreter() interpreter.translate_to_araxi(response) if response.status != 'OK': print(response.show(level=ARAXResponse.DEBUG)) return response araxi_commands = response.data['araxi_commands'] for cmd in araxi_commands: print(f" - {cmd}") #### Show the final result # print('-------------------------') # print(response.show(level=ARAXResponse.DEBUG)) # print(json.dumps(message.to_dict(),sort_keys=True,indent=2)) #### Actually run the query from ARAX_query import ARAXQuery import ast araxq = ARAXQuery() # Run the query araxq.query({**input_query_graph, "operations": {"actions": araxi_commands}}) # unpack the response response = araxq.response envelope = response.envelope message = envelope.message # overrides the current message envelope.status = response.error_code envelope.description = response.message # return the message ID print(f"Returned response id: {envelope.id}") print('-------------------------') # print the whole message # print(json.dumps(ast.literal_eval(repr(envelope)), sort_keys=True, indent=2)) # save message to file (since I can't get the UI working locally for some reason) with open('QGI_test7.json', 'w', encoding='utf-8') as f: json.dump(ast.literal_eval(repr(envelope)), f, ensure_ascii=False, indent=4)
def __connect_nodes(self, describe=False): """ Connects qnodes and runs expand. Allowable parameters: {'edge_predicate': str, 'edge_property': str, 'direction': {'above', 'below'}} :return: """ message = self.message parameters = self.parameters # make a list of the allowable parameters (keys), and their possible values (values). Note that the action and corresponding name will always be in the allowable parameters if message and parameters and hasattr(message, 'query_graph') and hasattr(message.query_graph, 'nodes'): allowable_parameters = {'action': {'connect_nodes'}, 'shortest_path': {'true', 'false', 'True', 'False', 't', 'f', 'T', 'F'}, 'max_path_length': {int()}, 'qnode_keys': set(self.message.query_graph.nodes.keys()) } else: allowable_parameters = {'action': {'connect_nodes'}, 'shortest_path': {'true', 'false', 'True', 'False', 't', 'f', 'T', 'F'}, 'max_path_length': {'a maximum path length to use to connect qnodes. Defaults to 2.'}, 'qnode_keys':{'a list of query node keys to connect'} } # A little function to describe what this thing does if describe: allowable_parameters['brief_description'] = self.command_definitions['connect_nodes'] return allowable_parameters # Make sure only allowable parameters and values have been passed resp = self.check_params(allowable_parameters) # return if bad parameters have been passed if self.response.status != 'OK' or resp == -1: return self.response # Set defaults and check parameters: if 'shortest_path' in self.parameters: if self.parameters['shortest_path'] in {'true', 'True', 't', 'T'}: self.parameters['shortest_path'] = True elif self.parameters['shortest_path'] in {'false', 'False', 'f', 'F'}: self.parameters['shortest_path'] = False else: self.parameters['shortest_path'] = True if 'qnode_keys' not in self.parameters or len(self.parameters['qnode_keys']) == 0: self.parameters['qnode_keys'] = list(set(self.message.query_graph.nodes.keys())) if len(self.parameters['qnode_keys']) < 2: self.response.error( f"Query graph must have at least 2 nodes to connect.", error_code="QueryGraphError") elif len(self.parameters['qnode_keys']) == 1: self.response.error( f"If qnode keys are provided you must provide at least 2 qnode keys.", error_code="ValueError") if 'max_path_length' not in self.parameters: self.parameters['max_path_length'] = 2 if self.parameters['max_path_length'] < 1 or self.parameters['max_path_length'] > 5: self.response.error( f"Maximum path length must be betwen 1 and 5 inclusive.", error_code="ValueError") if self.response.status != 'OK': return self.response expander = ARAXExpander() messenger = ARAXMessenger() # Expand parameters mode = 'ARAX' timeout = 60 kp = 'infores:rtx-kg2' prune_threshold = 500 qnode_key_pairs = [[x[0],x[1],False] for x in combinations(self.parameters['qnode_keys'], 2)] edge_n = 1 node_n = 1 # FW: old way, try running all pairs through at once # for qnode_pair in qnode_key_pairs: # added_connection = False # for n_new_nodes in range(self.parameters['max_path_length']): # new_response = ARAXResponse() # messenger.create_envelope(new_response) # new_response.envelope.message.query_graph.nodes = {k:v for k,v in self.response.envelope.message.query_graph.nodes.items() if k in qnode_pair} # qedge_keys = [] # node_pair_list = [qnode_pair[0]] # for i in range(n_new_nodes): # new_qnode_key = f'arax_connect_node_{node_n}' # node_n += 1 # # make new names until we find a node key not in the query graph # while new_qnode_key in self.response.envelope.message.query_graph.nodes: # new_qnode_key = f'arax_connect_node_{node_n}' # node_n += 1 # node_pair_list.append(new_qnode_key) # add_qnode_params = { # 'is_set' : 'true', # 'key' : new_qnode_key # } # new_response = messenger.add_qnode(new_response, add_qnode_params) # node_pair_list.append(qnode_pair[1]) # assert len(node_pair_list) == 2 + n_new_nodes # # This zip command grabs nodes next to each other and puts them into tuple pairs # # E.G. [1,2,3,4,5] -> [(1,2),(2,3),(3,4),(4,5)] # new_qnode_key_pairs = list(zip(node_pair_list,node_pair_list[1:])) # for new_qnode_pair in new_qnode_key_pairs: # new_qedge_key = f'connected_edge_{edge_n}' # edge_n += 1 # # make new names until we find an edge key not in the query graph # while new_qedge_key in self.response.envelope.message.query_graph.edges: # new_qedge_key = f'arax_connect_edge_{edge_n}' # edge_n += 1 # qedge_keys.append(new_qedge_key) # add_qedge_params = { # 'key' : new_qedge_key, # 'subject' : new_qnode_pair[0], # 'object' : new_qnode_pair[1] # } # new_response = messenger.add_qedge(new_response, add_qedge_params) # expand_params = { # # FW: commenting to reach out to all kps # #'kp':kp, # 'prune_threshold':prune_threshold, # 'edge_key':qedge_keys, # 'kp_timeout':timeout # } # new_response = expander.apply(new_response, expand_params, mode=mode) # if new_response.status == 'OK' and len(new_response.envelope.message.knowledge_graph.edges) > len(self.response.envelope.message.knowledge_graph.edges): # added_connection = True # # FW: confirm with Eric that this is the correct way to merge response objects # self.response.envelope.message.query_graph.edges.update(new_response.envelope.message.query_graph.edges) # self.response.envelope.message.query_graph.nodes.update(new_response.envelope.message.query_graph.nodes) # self.response.envelope.message.knowledge_graph.edges.update(new_response.envelope.message.knowledge_graph.edges) # self.response.envelope.message.knowledge_graph.nodes.update(new_response.envelope.message.knowledge_graph.nodes) # self.response.merge(new_response) # # FW: If we do not want to stop when we find the shortest connection we could add an option # # for shortest path and then check that here to deside if we want to break # if self.parameters['shortest_path']: # break # if not added_connection: # #FW: may want to change this to an error # self.response.warning(f"Could not connect the nodes {qnode_pair[0]} and {qnode_pair[1]} with a max path length of {self.parameters['max_path_length']}.") # FW: New way for n_new_nodes in range(self.parameters['max_path_length']): added_connection = False for qnode_pair in qnode_key_pairs: if qnode_pair[2]: continue new_response = ARAXResponse() messenger.create_envelope(new_response) new_response.envelope.message.query_graph.nodes = {k:v for k,v in self.response.envelope.message.query_graph.nodes.items() if k in qnode_pair} qedge_keys = [] node_pair_list = [qnode_pair[0]] for i in range(n_new_nodes): new_qnode_key = f'arax_connect_node_{node_n}' node_n += 1 # make new names until we find a node key not in the query graph while new_qnode_key in self.response.envelope.message.query_graph.nodes: new_qnode_key = f'arax_connect_node_{node_n}' node_n += 1 node_pair_list.append(new_qnode_key) add_qnode_params = { 'is_set' : 'true', 'key' : new_qnode_key } new_response = messenger.add_qnode(new_response, add_qnode_params) node_pair_list.append(qnode_pair[1]) assert len(node_pair_list) == 2 + n_new_nodes # This zip command grabs nodes next to each other and puts them into tuple pairs # E.G. [1,2,3,4,5] -> [(1,2),(2,3),(3,4),(4,5)] new_qnode_key_pairs = list(zip(node_pair_list,node_pair_list[1:])) for new_qnode_pair in new_qnode_key_pairs: new_qedge_key = f'connected_edge_{edge_n}' edge_n += 1 # make new names until we find an edge key not in the query graph while new_qedge_key in self.response.envelope.message.query_graph.edges: new_qedge_key = f'arax_connect_edge_{edge_n}' edge_n += 1 qedge_keys.append(new_qedge_key) add_qedge_params = { 'key' : new_qedge_key, 'subject' : new_qnode_pair[0], 'object' : new_qnode_pair[1] } new_response = messenger.add_qedge(new_response, add_qedge_params) expand_params = { # FW: commenting to reach out to all kps #'kp':kp, 'prune_threshold':prune_threshold, 'edge_key':qedge_keys, 'kp_timeout':timeout } new_response = expander.apply(new_response, expand_params, mode=mode) if new_response.status == 'OK' and len(new_response.envelope.message.knowledge_graph.edges) > len(self.response.envelope.message.knowledge_graph.edges): added_connection = True # FW: confirm with Eric that this is the correct way to merge response objects self.response.envelope.message.query_graph.edges.update(new_response.envelope.message.query_graph.edges) self.response.envelope.message.query_graph.nodes.update(new_response.envelope.message.query_graph.nodes) self.response.envelope.message.knowledge_graph.edges.update(new_response.envelope.message.knowledge_graph.edges) for knode_id, knode in new_response.envelope.message.knowledge_graph.nodes.items(): if knode_id in self.response.envelope.message.knowledge_graph.nodes: new_response.envelope.message.knowledge_graph.nodes[knode_id].qnode_keys += self.response.envelope.message.knowledge_graph.nodes[knode_id].qnode_keys self.response.envelope.message.knowledge_graph.nodes[knode_id].qnode_keys = new_response.envelope.message.knowledge_graph.nodes[knode_id].qnode_keys self.response.envelope.message.knowledge_graph.nodes.update(new_response.envelope.message.knowledge_graph.nodes) self.response.merge(new_response) # FW: If we do not want to stop when we find the shortest connection we could add an option # for shortest path and then check that here to deside if we want to break if self.parameters['shortest_path']: qnode_pair[2] = True if not added_connection: #FW: may want to change this to an error self.response.warning(f"Could not connect the nodes {qnode_pair[0]} and {qnode_pair[1]} with a max path length of {self.parameters['max_path_length']}.") return self.response