Beispiel #1
0
 def validateRequestBody(self):
     """
     Verify its a valid TRAPI request
     :return: None
     :raises: Will raise if not valid
     """
     reasoner_validator.validate(self.requestBody, "Query", trapi_version)
def validate_trapi(request_json: dict):
    """Return request verbatim if it is a valid TRAPI query."""
    try:
        validate(request_json, "Query", "1.1.0")
    except ValidationError as err:
        raise HTTPException(422, str(err))
    return request_json
Beispiel #3
0
def test_edgebinding():
    """Test validate_EdgeBinding()."""
    validate({
        "id": "hello",
    }, "EdgeBinding", "1.0.3")
    with pytest.raises(ValidationError):
        validate({
            "foo": {},
        }, "EdgeBinding", "1.0.3")
Beispiel #4
0
def test_query():
    """Test validate()."""
    validate({
        "message": {},
    }, "Query", "1.0.3")
    with pytest.raises(ValidationError):
        validate({
            "foo": {},
            "bar": {},
        }, "Query", "1.0.3")
Beispiel #5
0
def test_version_completion():
    """Test validate() with version completion."""
    validate({
        "message": {},
    }, "Query", "1.0")
    with pytest.raises(ValidationError):
        validate({
            "foo": {},
            "bar": {},
        }, "Query", "1")
Beispiel #6
0
def test_nullable():
    """Test nullable property."""
    qnode = {"category": None}
    validate(qnode, "QNode", "1.0.3")

    message = {
        "knowledge_graph": None,
        "query_graph": None,
        "results": None,
    }
    validate(message, "Message", "1.0.3")
 def userRequestBodyValidation(self):
     """
     A function to evaluate whether the JSON body received from the client conforms to the proper input standard.
     :return: Boolean: True meaning the body is valid, False meaning the body is not valid
     """
     try:
         # reasoner_validator.validate_Query(self.userRequestBody)
         reasoner_validator.validate(self.userRequestBody, "Query",
                                     trapi_version)
         return {"isValid": True, "error": None}
     except ValidationError as e:
         return {"isValid": False, "error": e}
def test_trapi_empty_response():
    reasoner_query = {
        "message": {
            "query_graph": {
                "edges": {
                    "e00": {
                        "subject": "n00",
                        "object": "n01",
                        "predicates": ["biolink:physically_interacts_with"]
                    }
                },
                "nodes": {
                    "n00": {
                        "ids": ["CHEMBL.COMPOUND:CHEMBL112"]
                    },
                    "n01": {
                        "categories": ["biolink:Protein"]
                    }
                }
            }
        }
    }

    response = client.post(
        '/query',
        data=json.dumps(reasoner_query),
        headers={"Content-Type": "application/json"},
        # content_type='application/json'
    )

    print(response.json)
    assert validate(response.json()['message'], "Message",
                    settings.TRAPI_VERSION_TEST) == None
    assert len(response.json()['message']['results']) == 0
def test_post_trapi():
    """Test Translator ReasonerAPI query POST operation to get predictions"""
    url = '/query'
    for trapi_filename in os.listdir(
            pkg_resources.resource_filename('tests', 'queries')):
        with open(
                pkg_resources.resource_filename('tests',
                                                'queries/' + trapi_filename),
                'r') as f:
            reasoner_query = f.read()
            response = client.post(
                url,
                data=reasoner_query,
                headers={"Content-Type": "application/json"},
                # content_type='application/json'
            )

            # print(response.json)
            edges = response.json(
            )['message']['knowledge_graph']['edges'].items()
            # print(response)
            print(trapi_filename)
            assert validate(response.json()['message'], "Message",
                            settings.TRAPI_VERSION_TEST) == None
            if trapi_filename.endswith('limit3.json'):
                assert len(edges) == 3
            elif trapi_filename.endswith('limit1.json'):
                assert len(edges) == 1
            else:
                assert len(edges) >= 5
Beispiel #10
0
 def validateResponseBody(self):
     """
     Verify its a valid TRAPI response
     :return: None
     :raises: Will raise InvalidSchema if not valid
     """
     try:
         # reasoner_validator.validate_Response(self.responseBody)
         reasoner_validator.validate(self.responseBody, "Response", trapi_version)
     except ValidationError as e:
         self.logs.append(clsLogEvent(
             identifier=self.name,
             level="ERROR",
             code="KPMalformedResponse",
             message=f"Knowledge Provider {self.url} did not return a valid TRAPI v1.2 response"
         ))
         raise requests.exceptions.InvalidSchema  # force raise a request.exception to know its the KP's fault
    def userResponseBodyValidation(self):
        """
        A function to evaluate whether the JSON body sent to the client conforms to the proper input standard.
        :return: Boolean: True meaning the body is valid, False meaning the body is not valid
        """
        validity_status = {"isValid": True, "error": None}

        # ensure all edge attribute lists end with the Explanatory Agent provenance attribute
        try:
            if self.userResponseBody['message'][
                    'knowledge_graph'] and "edges" in self.userResponseBody[
                        'message']['knowledge_graph']:
                for edge_id, edge in self.userResponseBody['message'][
                        'knowledge_graph']['edges'].items():
                    last_attribute = edge['attributes'][-1]
                    assert last_attribute[
                        "attribute_type_id"] == "biolink:aggregator_knowledge_source", "Edge missing xARA provenance data"
                    assert last_attribute[
                        "attribute_source"] == "infores:explanatory-agent", "Edge missing xARA provenance data"
        except AssertionError as e:
            self.logs.append(
                clsLogEvent(
                    identifier="",
                    level="DEBUG",
                    code="",
                    message=f"Provenance assertion failure: {e}").dict())
            # validity_status = {"isValid": False, "error": e}
        except Exception as e:
            self.logs.append(
                clsLogEvent(
                    identifier="",
                    level="DEBUG",
                    code="",
                    message=f"Provenance assertion failure: {e}").dict())

        try:
            reasoner_validator.validate(self.userResponseBody, "Response",
                                        trapi_version)
        except ValidationError as e:
            validity_status = {"isValid": False, "error": e}

        return validity_status
Beispiel #12
0
def test_post_trapi():
    """Test Translator ReasonerAPI query POST operation to get predictions"""
    headers = {'Content-type': 'application/json'}

    for trapi_filename in os.listdir(
            pkg_resources.resource_filename('tests', 'queries')):

        with open(
                pkg_resources.resource_filename('tests',
                                                'queries/' + trapi_filename),
                'r') as f:
            trapi_query = f.read()
            trapi_results = requests.post(PROD_API_URL + '/query',
                                          data=trapi_query,
                                          headers=headers).json()
            edges = trapi_results['message']['knowledge_graph']['edges'].items(
            )

            print(trapi_filename)
            assert validate(trapi_results['message'], "Message",
                            VALIDATE_TRAPI_VERSION) == None
            if trapi_filename.endswith('limit3.json'):
                assert len(edges) == 3
            elif trapi_filename.endswith('limit1.json'):
                assert len(edges) == 1
            else:
                assert len(edges) >= 5


# TODO: Check for this edge structure:
#   "knowledge_graph": {
#     "edges": {
#       "e0": {
#         "attributes": [
#           {
#             "name": "model_id",
#             "source": "OpenPredict",
#             "type": "EDAM:data_1048",
#             "value": "openpredict-baseline-omim-drugbank"
#           },
#           {
#             "name": "score",
#             "source": "OpenPredict",
#             "type": "EDAM:data_1772",
#             "value": "0.8267106697312154"
#           }
#         ],
#         "object": "DRUGBANK:DB00394",
#         "predicate": "biolink:treated_by",
#         "relation": "RO:0002434",
#         "subject": "OMIM:246300"
#       },
Beispiel #13
0
def main():

    #### Parse command line options
    import argparse
    argparser = argparse.ArgumentParser(
        description='CLI testing of the ResponseCache class')
    argparser.add_argument(
        '--verbose',
        action='count',
        help='If set, print more information about ongoing processing')
    #argparser.add_argument('list', action='store', help='List all local response ids')
    argparser.add_argument('response_id',
                           type=str,
                           nargs='*',
                           help='Id of a response to fetch and display')
    params = argparser.parse_args()

    #### Create a new ResponseStore object
    response_cache = ResponseCache()

    #### Get the session handle
    session = response_cache.session

    #### Query and print some rows from the reference tables
    #if params.list is True:
    if False:
        print("Listing of all responses")
        for response in session.query(Response).all():
            print(
                f"response_id={response.response_id}  response_datetime={response.response_datetime}"
            )
        return

    if len(params.response_id) > 0:
        print(f"Content of response_id {params.response_id[0]}:")
        envelope = response_cache.get_response(params.response_id[0])

        #print(json.dumps(ast.literal_eval(repr(envelope)), sort_keys=True, indent=2))
        #print(json.dumps(envelope, sort_keys=True, indent=2))
        print(json.dumps(envelope['logs'], sort_keys=True, indent=2))
        #return

    try:
        validate(envelope['message'], 'Message', trapi_version)
        print('- Message is valid')
    except ValidationError as error:
        print(f"- Message INVALID: {error}")

    #return

    for component, klass in {
            'query_graph': 'QueryGraph',
            'knowledge_graph': 'KnowledgeGraph'
    }.items():
        if component in envelope['message']:
            try:
                validate(envelope['message'][component], klass, trapi_version)
                print(f"  - {component} is valid")
            except ValidationError:
                print(f"  - {component} INVALID")
        else:
            print(f"  - {component} is not present")

    for node_key, node in envelope['message']['knowledge_graph'][
            'nodes'].items():
        print(f"{node_key}")
        for attribute in node['attributes']:
            attribute['value_type_id'] = None
            try:
                validate(attribute, 'Attribute', trapi_version)
                print(
                    f"  - attribute with {attribute['attribute_type_id']} is valid"
                )
            except ValidationError:
                print(
                    f"  - attribute with {attribute['attribute_type_id']} is  INVALID"
                )

    for result in envelope['message']['results']:
        try:
            validate(result, 'Result', trapi_version)
            print(f"    - result is valid")
        except ValidationError:
            print(f"    - result INVALID")

        for key, node_binding_list in result['node_bindings'].items():
            for node_binding in node_binding_list:
                try:
                    validate(node_binding, 'NodeBinding', trapi_version)
                    print(f"      - node_binding {key} is valid")
                except ValidationError:
                    print(f"      - node_binding {key} INVALID")

        for key, edge_binding_list in result['edge_bindings'].items():
            for edge_binding in edge_binding_list:
                #print(json.dumps(edge_binding, sort_keys=True, indent=2))
                try:
                    validate(edge_binding, 'EdgeBinding', trapi_version)
                    print(f"      - edge_binding {key} is valid")
                except ValidationError:
                    print(f"      - edge_binding {key} INVALID")
Beispiel #14
0
    def get_response(self, response_id):
        session = self.session

        if response_id is None:
            return ({
                "status": 400,
                "title": "response_id missing",
                "detail": "Required attribute response_id is missing from URL",
                "type": "about:blank"
            }, 400)

        response_id = str(response_id)

        #### Check to see if this is an integer. If so, it is a local response id
        match = re.match(r'\d+\s*$', response_id)
        if match:
            #### Find the response
            stored_response = session.query(Response).filter(
                Response.response_id == int(response_id)).first()
            if stored_response is not None:

                found_response_locally = False
                response_dir = os.path.dirname(
                    os.path.abspath(__file__)) + '/../../../data/responses_1_0'
                response_filename = f"{stored_response.response_id}.json"
                response_path = f"{response_dir}/{response_filename}"
                try:
                    with open(response_path) as infile:
                        envelope = json.load(infile)
                    found_response_locally = True
                except:
                    eprint(
                        f"ERROR: Unable to read response from file '{response_path}'. Will now try S3"
                    )

                #### If the file wasn't local, try it in S3
                if not found_response_locally:
                    rtx_config = RTXConfiguration()
                    KEY_ID = rtx_config.config["Global"]['s3']['access']
                    ACCESS_KEY = rtx_config.config["Global"]['s3']['secret']

                    try:
                        s3 = boto3.resource('s3',
                                            region_name='us-west-2',
                                            aws_access_key_id=KEY_ID,
                                            aws_secret_access_key=ACCESS_KEY)

                        response_filename = f"/responses/{response_id}.json"
                        eprint(
                            f"INFO: Attempting to read {response_filename} from S3"
                        )
                        t0 = timeit.default_timer()

                        content = s3.Object(
                            'arax-response-storage',
                            response_filename).get()["Body"].read()
                        envelope = json.loads(content)
                        t1 = timeit.default_timer()
                        print("Elapsed time: " + str(t1 - t0))
                        eprint(
                            f"INFO: Successfully read {response_filename} from S3 in {t1-t0} seconds"
                        )

                    except:
                        eprint(
                            f"ERROR: Unable to read {response_filename} from S3"
                        )
                        return ({
                            "status":
                            404,
                            "title":
                            "Response not found",
                            "detail":
                            "There is no response corresponding to response_id="
                            + str(response_id),
                            "type":
                            "about:blank"
                        }, 404)

                #### Perform a validation on it
                try:
                    validate(envelope, 'Response', trapi_version)
                    if 'description' not in envelope or envelope[
                            'description'] is None:
                        envelope['description'] = 'reasoner-validator: PASS'

                except ValidationError as error:
                    timestamp = str(datetime.now().isoformat())
                    if 'logs' not in envelope or envelope['logs'] is None:
                        envelope['logs'] = []
                    envelope['logs'].append({
                        "code":
                        'InvalidTRAPI',
                        "level":
                        "ERROR",
                        "message":
                        "TRAPI validator reported an error: " + str(error),
                        "timestamp":
                        timestamp
                    })
                    if 'description' not in envelope or envelope[
                            'description'] is None:
                        envelope['description'] = ''
                    envelope[
                        'description'] = 'ERROR: TRAPI validator reported an error: ' + str(
                            error) + ' --- ' + envelope['description']
                return envelope

            else:
                return ({
                    "status":
                    404,
                    "title":
                    "Response not found",
                    "detail":
                    "There is no response corresponding to response_id=" +
                    str(response_id),
                    "type":
                    "about:blank"
                }, 404)

        #### Otherwise, see if it is an ARS style response_id
        if len(response_id) > 30:
            ars_hosts = [
                'ars.transltr.io', 'ars-dev.transltr.io', 'ars.ci.transltr.io'
            ]
            for ars_host in ars_hosts:
                with requests_cache.disabled():
                    try:
                        response_content = requests.get(
                            f"https://{ars_host}/ars/api/messages/" +
                            response_id,
                            headers={'accept': 'application/json'})
                    except Exception as e:
                        return ({
                            "status": 404,
                            "title": f"Remote host {ars_host} unavailable",
                            "detail":
                            f"Connection attempts to {ars_host} triggered an exception: {e}",
                            "type": "about:blank"
                        }, 404)
                status_code = response_content.status_code
                #eprint(f"--- Fetch of {response_id} from {ars_host} yielded {status_code}")
                if status_code == 200:
                    break

            if status_code != 200:
                return ({
                    "status":
                    404,
                    "title":
                    "Response not found",
                    "detail":
                    "Cannot fetch from ARS a response corresponding to response_id="
                    + str(response_id),
                    "type":
                    "about:blank"
                }, 404)

            content_size = len(response_content.content)
            if content_size < 1000:
                content_size = '{:.2f} kB'.format(content_size / 1000)
            elif content_size < 1000000:
                content_size = '{:.0f} kB'.format(content_size / 1000)
            elif content_size < 10000000000:
                content_size = '{:.1f} MB'.format(content_size / 1000000)
            else:
                content_size = '{:.0f} MB'.format(content_size / 1000000)

            #### Unpack the response content into a dict
            try:
                response_dict = response_content.json()
            except:
                return ({
                    "status":
                    404,
                    "title":
                    "Error decoding Response",
                    "detail":
                    "Cannot decode ARS response_id=" + str(response_id) +
                    " to a Translator Response",
                    "type":
                    "about:blank"
                }, 404)

            if 'fields' in response_dict and 'actor' in response_dict[
                    'fields'] and str(response_dict['fields']['actor']) == '9':
                with requests_cache.disabled():
                    response_content = requests.get(
                        f"https://{ars_host}/ars/api/messages/" + response_id +
                        '?trace=y',
                        headers={'accept': 'application/json'})
                status_code = response_content.status_code

                if status_code != 200:
                    return ({
                        "status":
                        404,
                        "title":
                        "Response not found",
                        "detail":
                        "Failed attempting to fetch trace=y from ARS with response_id="
                        + str(response_id),
                        "type":
                        "about:blank"
                    }, 404)

                #### Unpack the response content into a dict and dump
                try:
                    response_dict = response_content.json()
                except:
                    return ({
                        "status":
                        404,
                        "title":
                        "Error decoding Response",
                        "detail":
                        "Cannot decode ARS response_id=" + str(response_id) +
                        " to a Translator Response",
                        "type":
                        "about:blank"
                    }, 404)

                return response_dict

            if 'fields' in response_dict and 'data' in response_dict['fields']:
                envelope = response_dict['fields']['data']
                if envelope is None:
                    envelope = {}
                    return envelope
                actual_response = str(envelope)
                if not isinstance(envelope, dict):
                    envelope = {'detail': envelope}

                #### Actor lookup
                actor_lookup = {
                    '1': 'Aragorn',
                    '2': 'ARAX',
                    '3': 'BTE',
                    '4': 'NCATS',
                    '5': 'Robokop',
                    '6': 'Unsecret',
                    '7': 'Genetics',
                    '8': 'MolePro',
                    '10': 'Explanatory',
                    '11': 'ImProving',
                    '12': 'Cam',
                    '13': 'TextMining'
                }

                #Remove warning code hack
                #if 'logs' in envelope and envelope['logs'] is not None:
                #    for log in envelope['logs']:
                #        if isinstance(log,dict):
                #            if 'code' in log and log['code'] is None:
                #                log['code'] = '-'
                is_trapi = True
                if 'message' in envelope:
                    #eprint("INFO: envelope has a message")
                    #eprint(json.dumps(envelope,indent=2,sort_keys=True))
                    if 'logs' in envelope and isinstance(
                            envelope['logs'],
                            list) and len(envelope['logs']) > 0:
                        #eprint("INFO: envelope has logs")
                        if isinstance(envelope['logs'][0], str):
                            #eprint("INFO: logs[0] is str")
                            is_trapi = False
                            actual_response = envelope['logs'][0]
                            for i in range(len(envelope['logs'])):
                                if isinstance(envelope['logs'][i], str):
                                    envelope['logs'][i] = {
                                        'level':
                                        'INFO',
                                        'message':
                                        'ARS info: ' + envelope['logs'][i]
                                    }

                            try:
                                #eprint(f"INFO: Actual response: {actual_response}")
                                import html
                                actual_response = html.unescape(
                                    actual_response)
                                #eprint(f"INFO: Actual decoded response: {actual_response}")
                                actual_response_dict = json.loads(
                                    actual_response)
                                if 'message' in actual_response_dict:
                                    is_trapi = True
                                    envelope = actual_response_dict
                            except:
                                eprint(
                                    "WARNING: tried to convert the response to JSON and it did not work"
                                )
                                eprint(f"It was: {envelope['logs'][0]}")

                else:
                    #eprint("INFO: envelope has no message")
                    is_trapi = False

                if not is_trapi:
                    envelope['validation_result'] = {
                        'status':
                        'NA',
                        'version':
                        trapi_version,
                        'size':
                        content_size,
                        'message':
                        'Returned response is not TRAPI: ' + actual_response
                    }
                    return envelope

                #### Perform a validation on it
                try:
                    validate(envelope, 'Response', trapi_version)
                    envelope['validation_result'] = {
                        'status': 'PASS',
                        'version': trapi_version,
                        'size': content_size,
                        'message': ''
                    }

                except ValidationError as error:
                    timestamp = str(datetime.now().isoformat())
                    if 'logs' not in envelope or envelope['logs'] is None:
                        envelope['logs'] = []
                    envelope['logs'].append({
                        "code":
                        'InvalidTRAPI',
                        "level":
                        "ERROR",
                        "message":
                        "TRAPI validator reported an error: " + str(error),
                        "timestamp":
                        timestamp
                    })
                    if 'description' not in envelope or envelope[
                            'description'] is None:
                        envelope['description'] = ''
                    envelope['validation_result'] = {
                        'status':
                        'FAIL',
                        'version':
                        trapi_version,
                        'size':
                        content_size,
                        'message':
                        'TRAPI validator reported an error: ' + str(error) +
                        ' --- ' + envelope['description']
                    }

                #### Try to add the reasoner_id
                if 'actor' in response_dict['fields'] and response_dict[
                        'fields']['actor'] is not None:
                    actor = str(response_dict['fields']['actor'])
                    if actor in actor_lookup:
                        if 'message' in envelope and 'results' in envelope[
                                'message'] and envelope['message'][
                                    'results'] is not None:
                            for result in envelope['message']['results']:
                                if 'reasoner_id' in result and result[
                                        'reasoner_id'] is not None:
                                    pass
                                else:
                                    result['reasoner_id'] = actor_lookup[actor]

                if 'message' in envelope and 'knowledge_graph' in envelope[
                        'message'] and envelope['message'][
                            'knowledge_graph'] is not None:
                    n_nodes = None
                    if 'nodes' in envelope['message'][
                            'knowledge_graph'] and envelope['message'][
                                'knowledge_graph']['nodes'] is not None:
                        n_nodes = len(
                            envelope['message']['knowledge_graph']['nodes'])
                    n_edges = None
                    if 'edges' in envelope['message'][
                            'knowledge_graph'] and envelope['message'][
                                'knowledge_graph']['edges'] is not None:
                        n_edges = len(
                            envelope['message']['knowledge_graph']['edges'])
                    envelope['validation_result']['n_nodes'] = n_nodes
                    envelope['validation_result']['n_edges'] = n_edges

                    #### Count provenance information
                    attribute_parser = ARAXAttributeParser(
                        envelope, envelope['message'])
                    envelope['validation_result'][
                        'provenance_summary'] = attribute_parser.summarize_provenance_info(
                        )

                return envelope
            return ({
                "status":
                404,
                "title":
                "Cannot find Response (in 'fields' and 'data') in ARS response packet",
                "detail":
                "Cannot decode ARS response_id=" + str(response_id) +
                " to a Translator Response",
                "type":
                "about:blank"
            }, 404)

        return ({
            "status": 404,
            "title": "UnrecognizedResponse_idFormat",
            "detail": "Unrecognized response_id format",
            "type": "about:blank"
        }, 404)
Beispiel #15
0
            iterateDictionary(value)


iterateDictionary(fileDataClean)

x = 5

nominal = {
    "query_graph": {
        "edges": {
            "e00": {
                "subject": "n00",
                "object": "n01",
                "type": "biolink:associated"
            }
        },
        "nodes": {
            "n00": {
                "curie": "EFO:0004465",
                "type": "biolink:Disease"
            },
            "n01": {
                "type": "biolink:Gene"
            }
        }
    }
}

reasoner_validator.validate(nominal)

x = 5