def test_format_attribute(): trapi_kg_response = { "knowledge_graph": { "nodes": { "CURIE:1": { "attributes": [{ "original_attribute_name": "pub", "attribute_type_id": "CURIE:x" }] } } } } expected_trapi = { "knowledge_graph": { "nodes": { "CURIE:1": { "attributes": [{ "attribute_type_id": "CURIE:x", "value_type_id": "biolink:Attribute", "original_attribute_name": "pub" }] } } } } q = Question(question_json={}) # test if attribute_id if provided from neo4j response is preserved # test if value_type is added to default 'biolink:Attribute' assert q.transform_attributes(trapi_kg_response) == expected_trapi expected_trapi = { "knowledge_graph": { "nodes": { "CURIE:1": { "attributes": [{ "attribute_type_id": "EDAM:data_0006", "value": "x", "original_attribute_name": "pub", "value_type_id": "oo" }] } } } } trapi_kg_response = { "knowledge_graph": { "nodes": { "CURIE:1": { "attributes": [{ "original_attribute_name": "pub", "value": "x", "value_type_id": "oo" }] } } } } # test default attribute to be EDAM:data_0006 # test if value_type is preserved if in response from neo4j assert q.transform_attributes(trapi_kg_response) == expected_trapi
async def annotate_node(self, message): node_ids = list(message['knowledge_graph'].get('nodes').keys()) node_ids = cypher_expression.dumps(node_ids) # skip name , id , categories from being returned in attributes array core_properties = cypher_expression.dumps(RESERVED_NODE_PROPS + ['name']) # mapping for attributes attribute_types = cypher_expression.dumps(ATTRIBUTE_TYPES) response = self.graph_interface.convert_to_dict( await self.graph_interface.get_nodes(node_ids, core_properties, attribute_types))[0]['result'] response = Question({}).format_attribute_trapi(response, self.graph_interface) # overides based on original attribute names for n_id in message['knowledge_graph']['nodes']: current_node = message['knowledge_graph']['nodes'][n_id] # get node from db from_db = response.get(n_id, {}) # skip if node is empty if not from_db: continue result = self.merge_attributes( attributes_msg=current_node.get('attributes') or [], attributes_neo=from_db.get('attributes') or []) # override categories and name if they exist from db else preserve original current_node['categories'] = from_db.get( 'categories') or current_node.get('categories') current_node['name'] = from_db.get('name') or current_node.get( 'name') # set attributes of new node to merged attributes current_node['attributes'] = result message['knowledge_graph']['nodes'][n_id] = current_node return message
def test_answer(): def compile_cypher_mock(): return "SOME CYPHER" question = Question({"query_graph": {}}) question.compile_cypher = compile_cypher_mock graph_interface = MOCK_GRAPH_ADAPTER() result = asyncio.run(question.answer(graph_interface=graph_interface)) expected_result = graph_interface.convert_to_dict('')[0] expected_result.update({"query_graph": {}}) assert result == expected_result
async def reasoner_api( request: ReasonerRequest = Body( ..., example=get_example("reasoner-trapi-1.2"), ), graph_interface: GraphInterface = Depends(get_graph_interface), ): """Handle TRAPI request.""" request_json = request.dict(by_alias=True) # default workflow workflow = request_json.get('workflow') or [{"id": "lookup"}] workflows = {wkfl['id']: wkfl for wkfl in workflow} if 'lookup' in workflows: question = Question(request_json["message"]) response = await question.answer(graph_interface) request_json.update({'message': response, 'workflow': workflow}) elif 'overlay_connect_knodes' in workflows: overlay = Overlay(graph_interface=graph_interface) response = await overlay.connect_k_nodes(request_json['message']) request_json.update({'message': response, 'workflow': workflow}) elif 'annotate_nodes' in workflows: overlay = Overlay(graph_interface=graph_interface) response = await overlay.annotate_node(request_json['message']) request_json.update({'message': response, 'workflow': workflow}) return request_json
def structure_for_easy_lookup(self, result_set): """ Converts apoc result into a mini graph :param result_set: :return: """ result = {} for r in result_set: edge = r['edge'] core_attributes = ['subject', 'object', 'predicate', 'id'] attributes = [] new_edge = {attr: r['edge'][attr] for attr in core_attributes} for attribute in edge: if attribute not in core_attributes: attributes.append({ 'original_attribute_name': attribute, 'value': edge[attribute] }) new_edge['attributes'] = attributes edge = Question({}).format_attribute_trapi({'edge': new_edge})['edge'] source_id = edge['subject'] target_id = edge['object'] m = result.get(source_id, {}) n = m.get(target_id, list()) n.append(edge) m[target_id] = n result[source_id] = m return result
async def reasoner_api( request: ReasonerRequest = Body( ..., example={"message": get_example("reasoner-trapi-1.1")}, ), graph_interface: GraphInterface = Depends(get_graph_interface), ): """Handle TRAPI request.""" request_json = request.dict(by_alias=True) question = Question(request_json["message"]) response = await question.answer(graph_interface) request_json.update({'message': response}) return request_json
def test_init(): reasoner_dict = { "query_graph": { "nodes": { "n0": {}, "n1": {} }, "edges": { "e0": { "subject": "n0", "object": "n1" } } } } question = Question(reasoner_dict) assert question._question_json == reasoner_dict assert question._question_json == reasoner_dict
def test_format_attribute(): # note that this test does not run through the reasoner code that does the attribute mapping. # so the values in the expected results must account for that trapi_kg_response = { "knowledge_graph": { "nodes": { "CURIE:1": { "attributes": [{ "original_attribute_name": "pub", "attribute_type_id": "CURIE:x" }, { "original_attribute_name": "biolink:original_knowledge_source", "value": "infores:kg_source" }] } } } } expected_trapi = { "knowledge_graph": { "nodes": { "CURIE:1": { "attributes": [{ "original_attribute_name": "pub", "attribute_type_id": "CURIE:x", "value_type_id": "EDAM:data_0006" }, { "original_attribute_name": "biolink:original_knowledge_source", "value": "infores:kg_source", "attribute_type_id": "biolink:original_knowledge_source", "value_type_id": "biolink:InformationResource" }, { "attribute_type_id": "biolink:aggregator_knowledge_source", "value": "infores:automat.notspecified", "value_type_id": "biolink:InformationResource", "original_attribute_name": "biolink:aggregator_knowledge_source" }] } } } } q = Question(question_json={}) graph_interface = MOCK_GRAPH_ADAPTER() transformed = q.transform_attributes(trapi_kg_response, graph_interface=MOCK_GRAPH_ADAPTER) # test attribute_id if provided from neo4j response is preserved # test if value_type is added to default 'biolink:Attribute' assert transformed == expected_trapi t2_trapi_kg_response = { "knowledge_graph": { "nodes": { "CURIE:1": { "attributes": [{ "original_attribute_name": "pub", "value": "x", "value_type_id": "oo", "attribute_type_id": "preserved_attrib" }, { "original_attribute_name": "publications", "value": "x" }, { "original_attribute_name": "endogenous", "value": "false" }, { "original_attribute_name": "p-value", "value": "1.234" }, { "original_attribute_name": "chi-squared-statistic", "value": "2.345" }, { "original_attribute_name": "equivalent_identifiers", "attribute_type_id": "biolink:same_as", "value": ["some_identifier"] }, { "original_attribute_name": "biolink:original_knowledge_source", "value": "infores:kg_source" }] } } } } t2_expected_trapi = { 'knowledge_graph': { 'nodes': { 'CURIE:1': { 'attributes': [{ 'original_attribute_name': 'pub', 'value': 'x', 'value_type_id': 'EDAM:data_0006', 'attribute_type_id': 'preserved_attrib' }, { 'original_attribute_name': 'publications', 'value': 'x', 'value_type_id': 'EDAM:data_0006', 'attribute_type_id': 'biolink:publications' }, { 'original_attribute_name': 'endogenous', 'value': 'false', 'value_type_id': 'xsd:boolean', 'attribute_type_id': 'aragorn:endogenous' }, { 'original_attribute_name': 'p-value', 'value': '1.234', 'value_type_id': 'EDAM:data_0006', 'attribute_type_id': 'biolink:Attribute' }, { 'original_attribute_name': 'chi-squared-statistic', 'value': '2.345', 'value_type_id': 'EDAM:data_0006', 'attribute_type_id': 'biolink:Attribute' }, { "original_attribute_name": "equivalent_identifiers", "attribute_type_id": "biolink:same_as", "value": ["some_identifier"], 'value_type_id': 'metatype:uriorcurie' }, { "original_attribute_name": "biolink:original_knowledge_source", "value": "infores:kg_source", "attribute_type_id": "biolink:original_knowledge_source", "value_type_id": "biolink:InformationResource" }, { 'attribute_type_id': 'biolink:aggregator_knowledge_source', 'value': 'infores:automat.notspecified', 'value_type_id': 'biolink:InformationResource', 'original_attribute_name': 'biolink:aggregator_knowledge_source' }] } } } } q = Question(question_json={}) transformed = q.transform_attributes(t2_trapi_kg_response, graph_interface=MOCK_GRAPH_ADAPTER) # test default attribute to be EDAM:data_0006 # test if value_type is preserved if in response from neo4j assert transformed == t2_expected_trapi