Skip to content

Commit

Permalink
Merge branch 'main' into task/fix-release-gates
Browse files Browse the repository at this point in the history
  • Loading branch information
bergsalex authored Mar 20, 2024
2 parents 9034489 + aea093a commit 375df3b
Show file tree
Hide file tree
Showing 15 changed files with 637 additions and 94 deletions.
176 changes: 88 additions & 88 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
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"
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
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
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
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
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
38 changes: 37 additions & 1 deletion 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,9 @@
"tests.data", "security_jwt_RS256_keys.json"
)

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

Expand Down Expand Up @@ -88,8 +93,39 @@
),
}

# 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"),
}


## 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"
),
}


## 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")
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

Loading

0 comments on commit 375df3b

Please sign in to comment.