Skip to content

Commit

Permalink
Merge pull request #37 from TheJacksonLaboratory/G3-192-species-list-…
Browse files Browse the repository at this point in the history
…endpoint

G3-192 species endpoint
  • Loading branch information
francastell authored Mar 18, 2024
2 parents 03ab23e + dbde2be commit 95ea8bf
Show file tree
Hide file tree
Showing 9 changed files with 385 additions and 91 deletions.
176 changes: 88 additions & 88 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "geneweaver-api"
version = "0.3.0"
version = "0.3.0a01"
description = "The Geneweaver API"
authors = [
"Alexander Berger <[email protected]>",
Expand All @@ -21,7 +21,7 @@ python = "^3.9"
geneweaver-core = "^0.9.0a1"
fastapi = {extras = ["all"], version = "^0.99.1"}
uvicorn = {extras = ["standard"], version = "^0.24.0"}
geneweaver-db = "^0.3.0a11"
geneweaver-db = "^0.3.0a12"
psycopg-pool = "^3.1.7"
requests = "^2.31.0"
python-jose = {extras = ["cryptography"], version = "^3.3.0"}
Expand Down
3 changes: 2 additions & 1 deletion src/geneweaver/api/controller/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from fastapi import APIRouter, FastAPI, Security
from geneweaver.api import __version__
from geneweaver.api import dependencies as deps
from geneweaver.api.controller import genes, genesets, publications
from geneweaver.api.controller import genes, genesets, publications, species
from geneweaver.api.core.config import settings

app = FastAPI(
Expand All @@ -28,5 +28,6 @@
api_router.include_router(genesets.router)
api_router.include_router(genes.router)
api_router.include_router(publications.router)
api_router.include_router(species.router)

app.include_router(api_router, prefix=settings.API_PREFIX)
24 changes: 24 additions & 0 deletions src/geneweaver/api/controller/species.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Endpoints related to species."""
from typing import Optional

from fastapi import APIRouter, Depends, Query
from geneweaver.api import dependencies as deps
from geneweaver.api.services import species as species_service
from geneweaver.core.enum import GeneIdentifier
from typing_extensions import Annotated

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


@router.get("/")
def get_species(
cursor: Optional[deps.Cursor] = Depends(deps.cursor),
taxonomy_id: Annotated[
Optional[int], Query(format="int64", minimum=0, maxiumum=9223372036854775807)
] = None,
reference_gene_id_type: Optional[GeneIdentifier] = None,
) -> dict:
"""Get species."""
response = species_service.get_species(cursor, taxonomy_id, reference_gene_id_type)

return response
36 changes: 36 additions & 0 deletions src/geneweaver/api/services/species.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Service functions for Species."""

from typing import Optional

from fastapi.logger import logger
from geneweaver.core.enum import GeneIdentifier
from geneweaver.db import species as db_species
from psycopg import Cursor


def get_species(
cursor: Cursor,
taxonomy_id: Optional[int] = None,
reference_gene_id_type: Optional[GeneIdentifier] = None,
) -> dict:
"""Get species from DB.
@param cursor: DB cursor
@param taxonomy_id:
@param reference_gene_id_type:
@return: dictionary response (species).
"""
try:
species = db_species.get(cursor, taxonomy_id, reference_gene_id_type)
for species_record in species:
ref_gene_id_type = species_record.get("reference_gene_identifier", None)
if ref_gene_id_type:
species_record["reference_gene_identifier"] = GeneIdentifier(
ref_gene_id_type
)

return {"species": species}

except Exception as err:
logger.error(err)
raise err
43 changes: 43 additions & 0 deletions tests/controllers/test_species.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Tests for species API."""
from unittest.mock import patch

from tests.data import test_species_data

species_no_params = test_species_data.get("species_no_parameters")
species_by_taxonomy_id_10090 = test_species_data.get("species_by_taxonomy_id_10090")
species_by_gene_id_type_flybase = test_species_data.get(
"species_by_gene_id_type_flybase"
)


@patch("geneweaver.api.services.species.get_species")
def test_valid_species_url_req(mock_species_service_call, client):
"""Test valid url request to get species."""
mock_species_service_call.return_value = species_no_params

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

assert response.status_code == 200
assert response.json() == species_no_params


@patch("geneweaver.api.services.species.get_species")
def test_species_url_taxonomy_req(mock_species_service_call, client):
"""Test valid url request to get species."""
mock_species_service_call.return_value = species_by_taxonomy_id_10090

response = client.get(url="/api/species?taxonomy_id=10090")

assert response.status_code == 200
assert response.json() == species_by_taxonomy_id_10090


@patch("geneweaver.api.services.species.get_species")
def test_valid_species_url_gene_id_type_req(mock_species_service_call, client):
"""Test valid url request to get species."""
mock_species_service_call.return_value = species_by_gene_id_type_flybase

response = client.get(url="/api/species?gene_id_type=14")

assert response.status_code == 200
assert response.json() == species_by_gene_id_type_flybase
28 changes: 28 additions & 0 deletions tests/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import importlib.resources
import json

from geneweaver.core.enum import GeneIdentifier

## Load test data
# Opening JSON files
geneset_response_json = importlib.resources.read_text(
Expand All @@ -24,6 +26,7 @@
"tests.data", "security_jwt_RS256_keys.json"
)

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

## laod and returns JSON string as a dictionary

Expand Down Expand Up @@ -93,3 +96,28 @@
"test_private_key": json.loads(jwt_test_keys_json).get("private_key"),
"test_public_key": json.loads(jwt_test_keys_json).get("public_key"),
}


## Species test data
test_species_data = {
"species_no_parameters": json.loads(species_json).get("species_no_parameters"),
"species_by_taxonomy_id_10090": json.loads(species_json).get(
"species_by_taxonomy_id_10090"
),
"species_by_gene_id_type_flybase": json.loads(species_json).get(
"species_by_gene_id_type_flybase"
),
}


def get_species_db_resp(species_data: dict) -> dict:
"""Get species data as returned by DB."""
species = species_data.get("species")
for species_record in species:
ref_gene_id_type = species_record.get("reference_gene_identifier", None)
if ref_gene_id_type:
species_record["reference_gene_identifier"] = GeneIdentifier(
ref_gene_id_type
).as_int()

return species
92 changes: 92 additions & 0 deletions tests/data/species.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"species_no_parameters": {
"species": [
{
"id": 0,
"name": "",
"taxonomic_id": 0,
"reference_gene_identifier": null
},
{
"id": 3,
"name": "Rattus norvegicus",
"taxonomic_id": 10116,
"reference_gene_identifier": "RGD"
},
{
"id": 4,
"name": "Danio rerio",
"taxonomic_id": 7955,
"reference_gene_identifier": "ZFIN"
},
{
"id": 10,
"name": "Gallus gallus",
"taxonomic_id": 9031,
"reference_gene_identifier": "CGNC"
},
{
"id": 1,
"name": "Mus musculus",
"taxonomic_id": 10090,
"reference_gene_identifier": "MGI"
},
{
"id": 5,
"name": "Drosophila melanogaster",
"taxonomic_id": 7227,
"reference_gene_identifier": "FlyBase"
},
{
"id": 11,
"name": "Canis familiaris",
"taxonomic_id": 9615,
"reference_gene_identifier": "Entrez"
},
{
"id": 2,
"name": "Homo sapiens",
"taxonomic_id": 9606,
"reference_gene_identifier": "HGNC"
},
{
"id": 8,
"name": "Caenorhabditis elegans",
"taxonomic_id": 6239,
"reference_gene_identifier": "Wormbase"
},
{
"id": 9,
"name": "Saccharomyces cerevisiae",
"taxonomic_id": 559292,
"reference_gene_identifier": "SGD"
},
{
"id": 6,
"name": "Macaca mulatta",
"taxonomic_id": 9544,
"reference_gene_identifier": "Entrez"
}
]
},
"species_by_taxonomy_id_10090": {
"species": [
{
"id": 1,
"name": "Mus musculus",
"taxonomic_id": 10090,
"reference_gene_identifier": "MGI"
}
]
},
"species_by_gene_id_type_flybase": {
"species": [
{
"id": 5,
"name": "Drosophila melanogaster",
"taxonomic_id": 7227,
"reference_gene_identifier": "FlyBase"
}
]
}
}
70 changes: 70 additions & 0 deletions tests/services/test_species.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""Tests for publications Service."""

from unittest.mock import patch

import pytest
from geneweaver.api.services import species as species_service
from geneweaver.core.enum import GeneIdentifier

from tests.data import get_species_db_resp, test_species_data

species_no_params = get_species_db_resp(test_species_data.get("species_no_parameters"))
species_by_taxonomy_id_10090 = get_species_db_resp(
test_species_data.get("species_by_taxonomy_id_10090")
)
species_by_gene_id_type_flybase = get_species_db_resp(
test_species_data.get("species_by_gene_id_type_flybase")
)


@patch("geneweaver.api.services.species.db_species")
def test_get_species(mock_db_species):
"""Test get species no paramaters."""
mock_db_species.get.return_value = species_no_params

response = species_service.get_species(None)

assert response.get("species") == species_no_params


@patch("geneweaver.api.services.species.db_species")
def test_get_species_by_taxonomy_id(mock_db_species):
"""Test speccies by taxonomy id."""
mock_db_species.get.return_value = species_by_taxonomy_id_10090

response = species_service.get_species(None, taxonomy_id=10090)

assert response.get("species") == species_by_taxonomy_id_10090


@patch("geneweaver.api.services.species.db_species")
def test_get_species_by_gene_id_type(mock_db_species):
"""Test speccies by taxonomy id."""
mock_db_species.get.return_value = species_by_gene_id_type_flybase

response = species_service.get_species(
None, reference_gene_id_type=GeneIdentifier("FlyBase")
)

assert response.get("species") == species_by_gene_id_type_flybase


@patch("geneweaver.api.services.species.db_species")
def test_get_species_by_gene_id_type_and_taxonomy(mock_db_species):
"""Test speccies by taxonomy id."""
mock_db_species.get.return_value = species_by_gene_id_type_flybase

response = species_service.get_species(
None, reference_gene_id_type=GeneIdentifier("FlyBase"), taxonomy_id=7227
)

assert response.get("species") == species_by_gene_id_type_flybase


@patch("geneweaver.api.services.species.db_species")
def test_get_species_with_error(mock_db_species):
"""Test error in DB call."""
mock_db_species.get.side_effect = Exception("ERROR")

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

0 comments on commit 95ea8bf

Please sign in to comment.