Skip to content

Commit

Permalink
Merge pull request #38 from TheJacksonLaboratory/G3-194-gene-list-end…
Browse files Browse the repository at this point in the history
…point

G3 194 gene list endpoint
  • Loading branch information
francastell authored Mar 20, 2024
2 parents 95ea8bf + 5a7ad70 commit aea093a
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 5 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "geneweaver-api"
version = "0.3.0a01"
version = "0.3.0a02"
description = "The Geneweaver API"
authors = [
"Alexander Berger <alexander.berger@jax.org>",
Expand Down
46 changes: 45 additions & 1 deletion src/geneweaver/api/controller/genes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Endpoints related to genes."""
from typing import Optional

from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query
from geneweaver.api import dependencies as deps
from geneweaver.api.schemas.apimodels import (
GeneIdHomologReq,
Expand All @@ -10,10 +10,54 @@
GeneIdMappingResp,
)
from geneweaver.api.services import genes as genes_service
from geneweaver.core.enum import GeneIdentifier, Species
from typing_extensions import Annotated

from . import message as api_message

router = APIRouter(prefix="/genes", tags=["genes"])


@router.get("")
def get_genes(
cursor: Optional[deps.Cursor] = Depends(deps.cursor),
reference_id: Annotated[
Optional[str], Query(description=api_message.GENE_REFERENCE)
] = None,
gene_database: Optional[GeneIdentifier] = None,
species: Optional[Species] = None,
preferred: Annotated[
Optional[bool], Query(description=api_message.GENE_PREFERRED)
] = None,
limit: Annotated[
Optional[int],
Query(
format="int64",
minimum=0,
maxiumum=9223372036854775807,
description=api_message.LIMIT,
),
] = None,
offset: Annotated[
Optional[int],
Query(
format="int64",
minimum=0,
maxiumum=9223372036854775807,
description=api_message.OFFSET,
),
] = None,
) -> dict:
"""Get geneweaver list of genes."""
if limit is None:
limit = 100

response = genes_service.get_genes(
cursor, reference_id, gene_database, species, preferred, limit, offset
)
return response


@router.post("/homologs", response_model=GeneIdMappingResp)
def get_related_gene_ids(
gene_id_mapping: GeneIdHomologReq,
Expand Down
6 changes: 6 additions & 0 deletions src/geneweaver/api/controller/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@
UNEXPECTED_ERROR = "Unexpected Error"
GENE_IDENTIFIER_TYPE_VALUE_ERROR = "Invalid gene identifier type"
RECORD_NOT_FOUND_ERROR = "Record not found"

##FORM field descriptions
GENE_REFERENCE = "The reference id to search for"
GENE_PREFERRED = "Whether to search for preferred genes"
LIMIT = "The limit of results to return"
OFFSET = "The offset of results to return"
34 changes: 34 additions & 0 deletions src/geneweaver/api/services/genes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,40 @@
from psycopg import Cursor


def get_genes(
cursor: Cursor,
reference_id: Optional[str] = None,
gene_database: Optional[GeneIdentifier] = None,
species: Optional[Species] = None,
preferred: Optional[bool] = None,
limit: Optional[int] = None,
offset: Optional[int] = None,
) -> dict:
"""Get geneweaver genes from DB.
:param cursor: The database cursor.
:param reference_id: The reference id to search for.
:param gene_database: The gene database to search for.
:param species: The species to search for.
:param preferred: Whether to search for preferred genes.
:param limit: The limit of results to return.
:param offset: The offset of results to return.
"""
if limit is None:
limit = 100

try:
gene_list = db_gene.get(
cursor, reference_id, gene_database, species, preferred, limit, offset
)

except Exception as err:
logger.error(err)
raise err

return {"genes": gene_list}


def get_homolog_ids(
cursor: Cursor,
gene_id_list: Iterable,
Expand Down
38 changes: 37 additions & 1 deletion tests/controllers/test_genes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import json
from unittest.mock import patch

from tests.data import test_gene_homolog_data, test_gene_mapping_data
from tests.data import test_gene_homolog_data, test_gene_mapping_data, test_genes_data

# genes
genes_list_10 = test_genes_data.get("genes_list_10")

# gene homolog ids test data
gene_ids_homolog_req_1 = test_gene_homolog_data.get(
Expand Down Expand Up @@ -144,3 +147,36 @@ def test_gene_aon_mapping_invalid_post_data_(client):
url="/api/genes/mapping/aon", data=json.dumps({"test": "test"})
)
assert response.status_code == 422


@patch("geneweaver.api.services.genes.get_genes")
def test_valid_gene_get_req(mock_gene_call, client):
"""Test valid get genes request."""
mock_gene_call.return_value = genes_list_10

response = client.get(url="/api/genes")

print(response)
assert response.status_code == 200
assert response.json() == genes_list_10

response = client.get(url="/api/genes?limit=10")
assert response.status_code == 200
assert response.json() == genes_list_10


@patch("geneweaver.api.services.genes.get_genes")
def test_invalid_param_gene_get_req(mock_gene_call, client):
"""Test invalid get genes request parameters."""
mock_gene_call.return_value = genes_list_10

response = client.get(url="/api/genes?limit=abc")
assert response.status_code == 422
response = client.get(url="/api/genes?offset=abc")
assert response.status_code == 422
response = client.get(url="/api/genes?gene_database=abc")
assert response.status_code == 422
response = client.get(url="/api/genes?species=abc")
assert response.status_code == 422
response = client.get(url="/api/genes?preferred=abc")
assert response.status_code == 422
10 changes: 9 additions & 1 deletion tests/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

species_json = importlib.resources.read_text("tests.data", "species.json")

genes_json = importlib.resources.read_text("tests.data", "genes.json")

## laod and returns JSON string as a dictionary

# geneset test data
Expand Down Expand Up @@ -91,7 +93,7 @@
),
}

# Json web token keys data =
# Json web token keys data
test_jwt_keys_data = {
"test_private_key": json.loads(jwt_test_keys_json).get("private_key"),
"test_public_key": json.loads(jwt_test_keys_json).get("public_key"),
Expand All @@ -110,6 +112,11 @@
}


## geneweaver genes test data
test_genes_data = {
"genes_list_10": json.loads(genes_json).get("genes_list_10"),
}

def get_species_db_resp(species_data: dict) -> dict:
"""Get species data as returned by DB."""
species = species_data.get("species")
Expand All @@ -121,3 +128,4 @@ def get_species_db_resp(species_data: dict) -> dict:
).as_int()

return species

86 changes: 86 additions & 0 deletions tests/data/genes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"genes_list_10": {
"genes": [
{
"id": 1,
"reference_id": "MGI:87853",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 2,
"reference_id": "MGI:87854",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 3,
"reference_id": "MGI:87859",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 4,
"reference_id": "MGI:87860",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 5,
"reference_id": "MGI:87862",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 6,
"reference_id": "MGI:87863",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 7,
"reference_id": "MGI:87864",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 8,
"reference_id": "MGI:87866",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 9,
"reference_id": "MGI:87867",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
},
{
"id": 10,
"reference_id": "MGI:87868",
"gene_database": 10,
"species": 1,
"preferred": false,
"date": "2020-05-05"
}
]
}
}
37 changes: 36 additions & 1 deletion tests/services/test_gene.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import pytest
from geneweaver.api.services import genes

from tests.data import test_gene_homolog_data, test_gene_mapping_data
from tests.data import test_gene_homolog_data, test_gene_mapping_data, test_genes_data

# genes
genes_list_10 = test_genes_data.get("genes_list_10")

# gene homolog ids test data
gene_ids_homolog_req_1 = test_gene_homolog_data.get(
Expand Down Expand Up @@ -219,3 +222,35 @@ def test_get_aon_gene_map_error(mock_db_gene):
gene_id_aon_mapping_req_1.get("source_ids"),
gene_id_aon_mapping_req_1.get("species"),
)


@patch("geneweaver.api.services.genes.db_gene")
def test_get_gene_error(mock_db_gene):
"""Test error in DB call."""
mock_db_gene.get.side_effect = Exception("ERROR")

with pytest.raises(expected_exception=Exception):
genes.get(None)


@patch("geneweaver.api.services.genes.db_gene")
def test_get_gene(mock_db_gene):
"""Test error in DB call."""
mock_db_gene.get.return_value = genes_list_10

response = genes.get_genes(None)

assert response.get("error") is None
assert response.get("genes") == genes_list_10

response = genes.get_genes(
None,
gene_database=10,
species=1,
preferred=False,
reference_id="MGI:87853",
limit=10,
offset=10,
)

assert response.get("error") is None

0 comments on commit aea093a

Please sign in to comment.