From 0ab5e4f0020c2261029ab4e2d00b40b5c8658b8d Mon Sep 17 00:00:00 2001 From: francastell Date: Thu, 29 Feb 2024 14:21:59 -0500 Subject: [PATCH 1/3] G3-197 aon mapping intial commit --- src/geneweaver/api/controller/genes.py | 28 +++++++++++++++++++++---- src/geneweaver/api/schemas/apimodels.py | 27 ++++++++++++++++-------- src/geneweaver/api/services/genes.py | 27 ++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/geneweaver/api/controller/genes.py b/src/geneweaver/api/controller/genes.py index 37308c1..3d1695a 100644 --- a/src/geneweaver/api/controller/genes.py +++ b/src/geneweaver/api/controller/genes.py @@ -8,17 +8,19 @@ GeneIdHomologResp, GeneIdMappingReq, GeneIdMappingResp, + GeneIdMappingAonReq, + GeneIdMappingAonResp ) from geneweaver.api.services import genes as genes_service router = APIRouter(prefix="/genes", tags=["genes"]) -@router.post("/homologs", response_model=GeneIdHomologResp) +@router.post("/homologs", response_model=GeneIdMappingResp) def get_related_gene_ids( gene_id_mapping: GeneIdHomologReq, cursor: Optional[deps.Cursor] = Depends(deps.cursor), -) -> GeneIdHomologResp: +) -> GeneIdMappingResp: """Get homologous gene ids given list of gene ids.""" response = genes_service.get_homolog_ids( cursor, @@ -30,7 +32,7 @@ def get_related_gene_ids( ) resp_id_map = response.get("ids_map") - gene_id_mapping_resp = GeneIdHomologResp(gene_ids_map=resp_id_map) + gene_id_mapping_resp = GeneIdMappingResp(gene_ids_map=resp_id_map) return gene_id_mapping_resp @@ -39,7 +41,7 @@ def get_related_gene_ids( def get_genes_mapping( gene_id_mapping: GeneIdMappingReq, cursor: Optional[deps.Cursor] = Depends(deps.cursor), -) -> GeneIdHomologResp: +) -> GeneIdMappingResp: """Get gene ids mapping given list of gene ids and target gene identifier type.""" response = genes_service.get_gene_mapping( cursor, @@ -52,3 +54,21 @@ def get_genes_mapping( gene_id_mapping_resp = GeneIdMappingResp(gene_ids_map=resp_id_map) return gene_id_mapping_resp + + +@router.post("/mapping/aon", response_model=GeneIdMappingResp) +def get_genes_mapping_aon( + gene_id_mapping: GeneIdMappingAonReq, + cursor: Optional[deps.Cursor] = Depends(deps.cursor), +) -> GeneIdMappingResp: + """Get gene ids mapping given list of gene ids and target gene identifier type.""" + response = genes_service.get_gene_aon_mapping( + cursor, + gene_id_mapping.source_ids, + gene_id_mapping.target_species + ) + + resp_id_map = response.get("ids_map") + gene_id_mapping_resp = GeneIdMappingResp(gene_ids_map=resp_id_map) + + return gene_id_mapping_resp \ No newline at end of file diff --git a/src/geneweaver/api/schemas/apimodels.py b/src/geneweaver/api/schemas/apimodels.py index 6981324..c843ccf 100644 --- a/src/geneweaver/api/schemas/apimodels.py +++ b/src/geneweaver/api/schemas/apimodels.py @@ -5,12 +5,6 @@ from pydantic import BaseModel -class GeneIdHomologResp(BaseModel): - """Model for homolog gene id mapping.""" - - gene_ids_map: list[dict] - - class GeneIdHomologReq(BaseModel): """Model for homolog gene id mapping request.""" @@ -20,6 +14,17 @@ class GeneIdHomologReq(BaseModel): target_species: Optional[Species] = None source_species: Optional[Species] = None +class GeneIdHomologResp(BaseModel): + """Model for homolog gene id mapping.""" + + gene_ids_map: list[dict] + +class GeneIdMappingReq(BaseModel): + """Model for gene id mapping request.""" + + source_ids: List[str] + target_gene_id_type: GeneIdentifier + target_species: Species class GeneIdMappingResp(BaseModel): """Model for gene id mapping.""" @@ -27,9 +32,13 @@ class GeneIdMappingResp(BaseModel): gene_ids_map: list[dict] -class GeneIdMappingReq(BaseModel): - """Model for gene id mapping request.""" +class GeneIdMappingAonReq(BaseModel): + """Model for AON gene id mapping request.""" source_ids: List[str] - target_gene_id_type: GeneIdentifier target_species: Species + +class GeneIdMappingAonResp(BaseModel): + """Model for gene id mapping.""" + + gene_ids_map: list[dict] \ No newline at end of file diff --git a/src/geneweaver/api/services/genes.py b/src/geneweaver/api/services/genes.py index 078ef12..d731bf1 100644 --- a/src/geneweaver/api/services/genes.py +++ b/src/geneweaver/api/services/genes.py @@ -74,3 +74,30 @@ def get_gene_mapping( raise err return {"ids_map": ids_map} + + +def get_gene_aon_mapping( + cursor: Cursor, + source_ids: List[str], + target_species: Species, +) -> dict: + """Get gene identifier AON mappings. + + Get gene id mappings based on species and default gene identifier type. + + @param cursor: DB Cursor + @param source_ids: list of gene ids to search + @param target_species: target species identifier + @return: dictionary with id mappings. + """ + ids_map = None + try: + ids_map = db_gene.aon_mapping( + cursor, source_ids, target_species, + ) + + except Exception as err: + logger.error(err) + raise err + + return {"ids_map": ids_map} From b8659d7c44f6ee525de35e1f2006620859dc1e5d Mon Sep 17 00:00:00 2001 From: francastell Date: Fri, 1 Mar 2024 10:17:07 -0500 Subject: [PATCH 2/3] G3-197 gene aon mapping --- src/geneweaver/api/controller/genes.py | 14 ++++----- src/geneweaver/api/schemas/apimodels.py | 22 ++++---------- src/geneweaver/api/services/genes.py | 4 ++- tests/controllers/test_genes.py | 25 ++++++++++++++++ tests/data/__init__.py | 6 ++++ tests/data/gene_maping.json | 19 ++++++++++++ tests/services/test_gene.py | 40 +++++++++++++++++++++++-- 7 files changed, 101 insertions(+), 29 deletions(-) diff --git a/src/geneweaver/api/controller/genes.py b/src/geneweaver/api/controller/genes.py index 738c057..3f4f34a 100644 --- a/src/geneweaver/api/controller/genes.py +++ b/src/geneweaver/api/controller/genes.py @@ -5,11 +5,9 @@ from geneweaver.api import dependencies as deps from geneweaver.api.schemas.apimodels import ( GeneIdHomologReq, - GeneIdHomologResp, + GeneIdMappingAonReq, GeneIdMappingReq, GeneIdMappingResp, - GeneIdMappingAonReq, - GeneIdMappingAonResp ) from geneweaver.api.services import genes as genes_service @@ -40,8 +38,8 @@ def get_related_gene_ids( @router.post("/mapping", response_model=GeneIdMappingResp) def get_genes_mapping( gene_id_mapping: GeneIdMappingReq, - cursor: Optional[deps.Cursor] = Depends(deps.cursor) -) -> GeneIdHomologResp: + cursor: Optional[deps.Cursor] = Depends(deps.cursor), +) -> GeneIdMappingResp: """Get gene ids mapping.""" response = genes_service.get_gene_mapping( cursor, @@ -63,12 +61,10 @@ def get_genes_mapping_aon( ) -> GeneIdMappingResp: """Get gene ids mapping given list of gene ids and target gene identifier type.""" response = genes_service.get_gene_aon_mapping( - cursor, - gene_id_mapping.source_ids, - gene_id_mapping.target_species + cursor, gene_id_mapping.source_ids, gene_id_mapping.species ) resp_id_map = response.get("ids_map") gene_id_mapping_resp = GeneIdMappingResp(gene_ids_map=resp_id_map) - return gene_id_mapping_resp \ No newline at end of file + return gene_id_mapping_resp diff --git a/src/geneweaver/api/schemas/apimodels.py b/src/geneweaver/api/schemas/apimodels.py index 7b8cf6c..066339e 100644 --- a/src/geneweaver/api/schemas/apimodels.py +++ b/src/geneweaver/api/schemas/apimodels.py @@ -5,6 +5,12 @@ from pydantic import BaseModel +class GeneIdMappingResp(BaseModel): + """Model for gene id mapping response.""" + + gene_ids_map: list[dict] + + class GeneIdHomologReq(BaseModel): """Model for homolog gene id mapping request.""" @@ -14,10 +20,6 @@ class GeneIdHomologReq(BaseModel): target_species: Optional[Species] = None source_species: Optional[Species] = None -class GeneIdHomologResp(BaseModel): - """Model for homolog gene id mapping.""" - - gene_ids_map: list[dict] class GeneIdMappingReq(BaseModel): """Model for gene id mapping request.""" @@ -26,21 +28,9 @@ class GeneIdMappingReq(BaseModel): target_gene_id_type: GeneIdentifier species: Species -class GeneIdMappingResp(BaseModel): - """Model for gene id mapping.""" - - gene_ids_map: list[dict] - class GeneIdMappingAonReq(BaseModel): """Model for AON gene id mapping request.""" source_ids: List[str] - target_species: Species - -class GeneIdMappingAonResp(BaseModel): - """Model for gene id mapping.""" - - gene_ids_map: list[dict] species: Species - diff --git a/src/geneweaver/api/services/genes.py b/src/geneweaver/api/services/genes.py index e999f2c..f13ff3b 100644 --- a/src/geneweaver/api/services/genes.py +++ b/src/geneweaver/api/services/genes.py @@ -91,7 +91,9 @@ def get_gene_aon_mapping( ids_map = None try: ids_map = db_gene.aon_mapping( - cursor, source_ids, target_species, + cursor, + source_ids, + target_species, ) except Exception as err: diff --git a/tests/controllers/test_genes.py b/tests/controllers/test_genes.py index 6044e4b..fd1cefd 100644 --- a/tests/controllers/test_genes.py +++ b/tests/controllers/test_genes.py @@ -13,6 +13,8 @@ # gene id mapping test data gene_id_mapping_req_1 = test_gene_mapping_data.get("gene_mapping_req_1") gene_id_mapping_resp_1 = test_gene_mapping_data.get("gene_mapping_resp_1") +gene_id_aon_mapping_req_1 = test_gene_mapping_data.get("gene_aon_mapping_req_1") +gene_id_aon_mapping_resp_1 = test_gene_mapping_data.get("gene_aon_mapping_resp_1") @patch("geneweaver.api.services.genes.get_homolog_ids") @@ -119,3 +121,26 @@ def test_gene_mapping_invalid_post_data_(mock_gene_id_mapping, client): response = client.post(url="/api/genes/mapping", data=json.dumps({"test": "test"})) assert response.status_code == 422 + + +@patch("geneweaver.api.services.genes.get_gene_aon_mapping") +def test_gene_aon_mapping_valid_post_req(mock_gene_id_aon_mapping, client): + """Test genes mapping ids url and post request.""" + mock_gene_id_aon_mapping.return_value = { + "ids_map": gene_id_aon_mapping_resp_1.get("gene_ids_map") + } + + response = client.post( + url="/api/genes/mapping/aon", data=json.dumps(gene_id_aon_mapping_req_1) + ) + print(response) + assert response.status_code == 200 + assert response.json() == gene_id_aon_mapping_resp_1 + + +def test_gene_aon_mapping_invalid_post_data_(client): + """Test genes ids aon mapping url and invalid post data request.""" + response = client.post( + url="/api/genes/mapping/aon", data=json.dumps({"test": "test"}) + ) + assert response.status_code == 422 diff --git a/tests/data/__init__.py b/tests/data/__init__.py index f2a07d7..f9388c7 100644 --- a/tests/data/__init__.py +++ b/tests/data/__init__.py @@ -72,6 +72,12 @@ "gene_mapping_resp_2": json.loads(gene_id_mapping_json).get( "gene_mapping_response_2" ), + "gene_aon_mapping_req_1": json.loads(gene_id_mapping_json).get( + "gene_aon_mapping_request_1" + ), + "gene_aon_mapping_resp_1": json.loads(gene_id_mapping_json).get( + "gene_aon_mapping_response_1" + ), } # Publication test data diff --git a/tests/data/gene_maping.json b/tests/data/gene_maping.json index 12e0d60..ae637b1 100644 --- a/tests/data/gene_maping.json +++ b/tests/data/gene_maping.json @@ -39,5 +39,24 @@ "mapped_ref_id": "KLHL13" } ] + }, + "gene_aon_mapping_request_1": { + "source_ids": [ + "DAB1", + "SLC6A9" + ], + "species": "Homo Sapiens" + }, + "gene_aon_mapping_response_1": { + "gene_ids_map": [ + { + "original_ref_id": "DAB1", + "mapped_ref_id": "HGNC:2661" + }, + { + "original_ref_id": "SLC6A9", + "mapped_ref_id": "HGNC:11056" + } + ] } } \ No newline at end of file diff --git a/tests/services/test_gene.py b/tests/services/test_gene.py index 5144e08..087550e 100644 --- a/tests/services/test_gene.py +++ b/tests/services/test_gene.py @@ -27,6 +27,8 @@ gene_id_mapping_resp_1 = test_gene_mapping_data.get("gene_mapping_resp_1") gene_id_mapping_req_2 = test_gene_mapping_data.get("gene_mapping_req_2") gene_id_mapping_resp_2 = test_gene_mapping_data.get("gene_mapping_resp_2") +gene_id_aon_mapping_req_1 = test_gene_mapping_data.get("gene_aon_mapping_req_1") +gene_id_aon_mapping_resp_1 = test_gene_mapping_data.get("gene_aon_mapping_resp_1") @patch("geneweaver.api.services.genes.db_gene") @@ -147,7 +149,7 @@ def test_get_gene_map_mouse(mock_db_gene): response = genes.get_gene_mapping( None, gene_id_mapping_req_1.get("source_ids"), - gene_id_mapping_req_1.get("target_species"), + gene_id_mapping_req_1.get("species"), gene_id_mapping_req_1.get("target_gene_id_type"), ) @@ -165,7 +167,7 @@ def test_get_gene_map_human(mock_db_gene): response = genes.get_gene_mapping( None, gene_id_mapping_req_2.get("source_ids"), - gene_id_mapping_req_2.get("target_species"), + gene_id_mapping_req_2.get("species"), gene_id_mapping_req_2.get("target_gene_id_type"), ) @@ -182,6 +184,38 @@ def test_get_gene_map_error(mock_db_gene): genes.get_gene_mapping( None, gene_id_mapping_req_2.get("source_ids"), - gene_id_mapping_req_2.get("target_species"), + gene_id_mapping_req_2.get("species"), gene_id_mapping_req_2.get("target_gene_id_type"), ) + + +@patch("geneweaver.api.services.genes.db_gene") +def test_get_gene_aon_map(mock_db_gene): + """Test gene ids map by gene id type and species - Human.""" + mock_db_gene.aon_mapping.return_value = gene_id_aon_mapping_resp_1.get( + "gene_ids_map" + ) + + # Request: + # (source_ids, target gene id type, target species) + response = genes.get_gene_aon_mapping( + None, + gene_id_aon_mapping_req_1.get("source_ids"), + gene_id_aon_mapping_req_1.get("species"), + ) + + assert response.get("error") is None + assert response.get("ids_map") == gene_id_aon_mapping_resp_1.get("gene_ids_map") + + +@patch("geneweaver.api.services.genes.db_gene") +def test_get_aon_gene_map_error(mock_db_gene): + """Test error in DB call.""" + mock_db_gene.aon_mapping.side_effect = Exception("ERROR") + + with pytest.raises(expected_exception=Exception): + genes.get_gene_aon_mapping( + None, + gene_id_aon_mapping_req_1.get("source_ids"), + gene_id_aon_mapping_req_1.get("species"), + ) From 28d9c17275bf755adcb5492bad56a8eea25f9f0e Mon Sep 17 00:00:00 2001 From: francastell Date: Fri, 1 Mar 2024 12:25:26 -0500 Subject: [PATCH 3/3] G3-197 change species parameter --- src/geneweaver/api/services/genes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/geneweaver/api/services/genes.py b/src/geneweaver/api/services/genes.py index f13ff3b..32c7062 100644 --- a/src/geneweaver/api/services/genes.py +++ b/src/geneweaver/api/services/genes.py @@ -77,7 +77,7 @@ def get_gene_mapping( def get_gene_aon_mapping( cursor: Cursor, source_ids: List[str], - target_species: Species, + species: Species, ) -> dict: """Get gene identifier AON mappings. @@ -85,7 +85,7 @@ def get_gene_aon_mapping( @param cursor: DB Cursor @param source_ids: list of gene ids to search - @param target_species: target species identifier + @param species: target species identifier @return: dictionary with id mappings. """ ids_map = None @@ -93,7 +93,7 @@ def get_gene_aon_mapping( ids_map = db_gene.aon_mapping( cursor, source_ids, - target_species, + species, ) except Exception as err: