Skip to content

Commit 20ea78b

Browse files
committed
Merge branch 'api' into error-reporting
2 parents 4535bcd + 0b1c7c1 commit 20ea78b

File tree

7 files changed

+130
-1
lines changed

7 files changed

+130
-1
lines changed

Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ RUN pip install -e '.[dev,tests]'
4646
RUN pip install -U polars-lts-cpu
4747
# install gene normalizer with pg dependencies. TODO: can the pg dependencies be specified in pyproject.toml?
4848
#RUN pip install 'gene-normalizer[pg]'
49+
50+
# not working, needs to happen after db volume is mounted
51+
# ENV GENE_NORM_DB_URL=postgres://postgres:postgres@db:5432/gene_normalizer
52+
# RUN echo "y" | gene_norm_update_remote
53+
4954
ENV PYTHONUNBUFFERED 1
5055

5156
ENV PYTHONPATH "${PYTHONPATH}:/usr/src/app/src"
57+
58+
# Tell Docker that we will listen on port 8000.
59+
EXPOSE 8000
60+
61+
# At container startup, run the application using uvicorn.
62+
CMD ["uvicorn", "api.server_main:app", "--host", "0.0.0.0", "--port", "8000"]

docker-compose-dev.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ services:
3434
volumes:
3535
- vrs-mapping-seqrepo-dev:/usr/local/share/seqrepo
3636

37+
api:
38+
build:
39+
context: .
40+
command: bash -c "uvicorn api.server_main:app --host 0.0.0.0 --port 8000 --reload"
41+
depends_on:
42+
- db
43+
- seqrepo
44+
env_file:
45+
- settings/.env.dev
46+
ports:
47+
- "8004:8000"
48+
volumes:
49+
- .:/usr/src/app
50+
- vrs-mapping-seqrepo-dev:/usr/local/share/seqrepo
51+
3752
volumes:
3853
vrs-mapping-data-dev:
3954
vrs-mapping-seqrepo-dev:

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ dependencies = [
4242
"pydantic>=2",
4343
"python-dotenv",
4444
"setuptools>=68.0", # tmp -- ensure 3.12 compatibility
45-
"mavehgvs==0.6.1"
45+
"mavehgvs==0.6.1",
46+
"fastapi",
47+
"starlette",
48+
"uvicorn"
4649
]
4750
dynamic = ["version"]
4851

src/api/__init__.py

Whitespace-only changes.

src/api/routers/__init__.py

Whitespace-only changes.

src/api/routers/map.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from cool_seq_tool.schemas import AnnotationLayer
2+
from fastapi import APIRouter
3+
4+
from dcd_mapping.align import align
5+
from dcd_mapping.annotate import (
6+
_get_computed_reference_sequence,
7+
_get_mapped_reference_sequence,
8+
_set_scoreset_layer,
9+
annotate,
10+
)
11+
from dcd_mapping.mavedb_data import (
12+
get_raw_scoreset_metadata,
13+
get_scoreset_metadata,
14+
get_scoreset_records,
15+
)
16+
from dcd_mapping.schemas import ScoreAnnotation, ScoresetMapping
17+
from dcd_mapping.transcripts import select_transcript
18+
from dcd_mapping.vrs_map import vrs_map
19+
20+
router = APIRouter(
21+
prefix="/api/v1", tags=["mappings"], responses={404: {"description": "Not found"}}
22+
)
23+
24+
25+
@router.post(path="/map/{urn}", status_code=200, response_model=ScoresetMapping)
26+
async def map_scoreset(urn: str) -> ScoresetMapping:
27+
metadata = get_scoreset_metadata(urn)
28+
records = get_scoreset_records(urn, True)
29+
30+
alignment_result = align(metadata, True)
31+
32+
transcript = await select_transcript(metadata, records, alignment_result)
33+
34+
vrs_results = vrs_map(metadata, alignment_result, records, transcript, True)
35+
36+
# TODO raise server error if vrs_results is None
37+
if vrs_results is None:
38+
return None
39+
40+
vrs_results = annotate(vrs_results, transcript, metadata)
41+
42+
raw_metadata = get_raw_scoreset_metadata(urn)
43+
# TODO change vrs map back to always use only the preferred layer
44+
# preferred_layers = {mapping.annotation_layer for mapping in vrs_results}
45+
preferred_layers = {
46+
_set_scoreset_layer(urn, vrs_results),
47+
}
48+
49+
reference_sequences = {
50+
layer: {"computed_reference_sequence": None, "mapped_reference_sequence": None}
51+
for layer in AnnotationLayer
52+
}
53+
54+
for layer in preferred_layers:
55+
reference_sequences[layer][
56+
"computed_reference_sequence"
57+
] = _get_computed_reference_sequence(urn, layer, transcript)
58+
reference_sequences[layer][
59+
"mapped_reference_sequence"
60+
] = _get_mapped_reference_sequence(layer, transcript, alignment_result)
61+
62+
mapped_scores: list[ScoreAnnotation] = []
63+
for m in vrs_results:
64+
if m.annotation_layer in preferred_layers:
65+
# drop annotation layer from mapping object
66+
mapped_scores.append(ScoreAnnotation(**m.model_dump()))
67+
68+
output = ScoresetMapping(
69+
metadata=raw_metadata,
70+
computed_protein_reference_sequence=reference_sequences[
71+
AnnotationLayer.PROTEIN
72+
]["computed_reference_sequence"],
73+
mapped_protein_reference_sequence=reference_sequences[AnnotationLayer.PROTEIN][
74+
"mapped_reference_sequence"
75+
],
76+
computed_genomic_reference_sequence=reference_sequences[
77+
AnnotationLayer.GENOMIC
78+
]["computed_reference_sequence"],
79+
mapped_genomic_reference_sequence=reference_sequences[AnnotationLayer.GENOMIC][
80+
"mapped_reference_sequence"
81+
],
82+
mapped_scores=mapped_scores,
83+
)
84+
85+
return output

src/api/server_main.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""FastAPI server file"""
2+
import uvicorn
3+
from fastapi import FastAPI
4+
5+
from api.routers import map
6+
7+
app = FastAPI()
8+
9+
app.include_router(map.router)
10+
11+
12+
# If the application is not already being run within a uvicorn server, start uvicorn here.
13+
if __name__ == "__main__":
14+
uvicorn.run(app, host="0.0.0.0", port=8000)
15+

0 commit comments

Comments
 (0)