Skip to content

Commit 713f702

Browse files
move endpoint from 'main.py' into 'restapi/vlm.py'
1 parent 4d2121d commit 713f702

File tree

4 files changed

+92
-63
lines changed

4 files changed

+92
-63
lines changed

src/anyvlm/main.py

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,21 @@
22

33
from collections.abc import AsyncGenerator
44
from contextlib import asynccontextmanager
5-
from enum import Enum
6-
from http import HTTPStatus
7-
from typing import Annotated, Union
85

9-
from fastapi import FastAPI, HTTPException, Query, Request
6+
from fastapi import FastAPI
107

118
from anyvlm import __version__
129
from anyvlm.anyvar.base_client import BaseAnyVarClient
1310
from anyvlm.config import get_config
14-
from anyvlm.functions.get_caf import get_caf
1511
from anyvlm.schemas.common import (
1612
SERVICE_DESCRIPTION,
1713
ServiceInfo,
1814
ServiceOrganization,
1915
ServiceType,
2016
)
21-
from anyvlm.schemas.vlm import VlmResponse
22-
from anyvlm.utils.types import ChromosomeName, GenomicSequence, GrcAssemblyId, UscsAssemblyBuild
17+
from anyvlm.utils.types import (
18+
EndpointTag,
19+
)
2320

2421

2522
def create_anyvar_client(
@@ -63,18 +60,11 @@ async def lifespan(app: FastAPI) -> AsyncGenerator:
6360
)
6461

6562

66-
class _Tag(str, Enum):
67-
"""Define tag names for endpoints."""
68-
69-
META = "Meta"
70-
SEARCH = "Search"
71-
72-
7363
@app.get(
7464
"/service-info",
7565
summary="Get basic service information",
7666
description="Retrieve service metadata, such as versioning and contact info. Structured in conformance with the [GA4GH service info API specification](https://www.ga4gh.org/product/service-info/)",
77-
tags=[_Tag.META],
67+
tags=[EndpointTag.META],
7868
)
7969
def service_info() -> ServiceInfo:
8070
"""Provide service info per GA4GH Service Info spec"""
@@ -83,32 +73,3 @@ def service_info() -> ServiceInfo:
8373
type=ServiceType(),
8474
environment=get_config().env,
8575
)
86-
87-
88-
@app.get(
89-
"/vlm-query",
90-
summary="Provides counts of occurrences of a single sequence variant, broken down by zygosity",
91-
description="Provides counts of occurrences of a single sequence variant, broken down by zygosity", #TODO: Update this
92-
tags=[_Tag.SEARCH]
93-
)
94-
def vlm_query(
95-
request: Request,
96-
assemblyId: Annotated[GrcAssemblyId | UscsAssemblyBuild, Query(..., description="Genome reference assembly")],
97-
referenceName: Annotated[ChromosomeName, Query(..., description="Chromosome with optional 'chr' prefix")],
98-
start: Annotated[int, Query(..., description="Variant position")],
99-
referenceBases: Annotated[GenomicSequence, Query(..., description="Genomic bases ('T', 'AC', etc.)")],
100-
alternateBases: Annotated[GenomicSequence, Query(..., description="Genomic bases ('T', 'AC', etc.)")]
101-
) -> VlmResponse:
102-
103-
anyvar_client: BaseAnyVarClient = request.app.state.anyvar_client
104-
105-
caf_data = get_caf(
106-
anyvar_client,
107-
assemblyId,
108-
referenceName,
109-
start,
110-
referenceBases,
111-
alternateBases
112-
)
113-
114-
return VlmResponse() #TODO: fill this out. See Issue #16 and Issue #13

src/anyvlm/restapi/vlm.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
"""Define route(s) for the variant-level matching (VLM) protocol"""
22

33
from pathlib import Path
4+
from typing import Annotated
5+
6+
from fastapi import Query, Request
7+
8+
from anyvlm.anyvar.base_client import BaseAnyVarClient
9+
from anyvlm.functions.get_caf import get_caf
10+
from anyvlm.main import app
11+
from anyvlm.schemas.vlm import VlmResponse
12+
from anyvlm.utils.types import (
13+
ChromosomeName,
14+
EndpointTag,
15+
GenomicSequence,
16+
GrcAssemblyId,
17+
UscsAssemblyBuild,
18+
)
419

520

621
def ingest_vcf(vcf_path: Path) -> None:
@@ -9,3 +24,45 @@ def ingest_vcf(vcf_path: Path) -> None:
924
:param vcf_path: VCF file location
1025
"""
1126
raise NotImplementedError
27+
28+
29+
@app.get(
30+
"/vlm-query",
31+
summary="Provides counts of occurrences of a single sequence variant, broken down by zygosity",
32+
description="Provides counts of occurrences of a single sequence variant, broken down by zygosity", # TODO: Update this
33+
tags=[EndpointTag.SEARCH],
34+
)
35+
def vlm_query(
36+
request: Request,
37+
assemblyId: Annotated[ # noqa: N803
38+
GrcAssemblyId | UscsAssemblyBuild,
39+
Query(..., description="Genome reference assembly"),
40+
],
41+
referenceName: Annotated[ # noqa: N803
42+
ChromosomeName, Query(..., description="Chromosome with optional 'chr' prefix")
43+
],
44+
start: Annotated[int, Query(..., description="Variant position")],
45+
referenceBases: Annotated[ # noqa: N803
46+
GenomicSequence, Query(..., description="Genomic bases ('T', 'AC', etc.)")
47+
],
48+
alternateBases: Annotated[ # noqa: N803
49+
GenomicSequence, Query(..., description="Genomic bases ('T', 'AC', etc.)")
50+
],
51+
) -> VlmResponse:
52+
"""Accept a Variant-Level Matching network request and return a count of occurrences of a single sequence variant, broken down by zygosity.
53+
54+
:param request: FastAPI `Request` object
55+
:param assemblyId: The genome reference assembly. Must be a GRC assembly identifier (e.g., "GRCh38) or a USCS assembly build (e.g., "hg38")
56+
:param referenceName: The name of the reference chromosome, with optional 'chr' prefix
57+
:param start: The start of the variant's position
58+
:param referenceBases: Genomic bases ('T', 'AC', etc.)
59+
:param alternateBases: Genomic bases ('T', 'AC', etc.)
60+
:return: A VlmResponse object containing cohort allele frequency data. If no matches are found, endpoint will return a status code of 200 with an empty set of results.
61+
"""
62+
anyvar_client: BaseAnyVarClient = request.app.state.anyvar_client
63+
64+
caf_data = get_caf( # noqa: F841 - TODO: remove this noqa when endpoint is complete. See Issue #16 and Issue #13.
65+
anyvar_client, assemblyId, referenceName, start, referenceBases, alternateBases
66+
)
67+
68+
return VlmResponse() # TODO: fill this out. See Issue #16 and Issue #13

src/anyvlm/utils/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Provide utilities."""

src/anyvlm/utils/types.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
"""Provide helpful type definitions, references, and type-based operations."""
22

3-
from enum import StrEnum
3+
from enum import Enum, StrEnum
44
from typing import Annotated
55

66
from pydantic import BeforeValidator, StringConstraints
77

88

9+
class EndpointTag(str, Enum):
10+
"""Define tag names for endpoints."""
11+
12+
META = "Meta"
13+
SEARCH = "Search"
14+
15+
916
class GrcAssemblyId(StrEnum):
1017
"""Supported GRC assembly identifiers"""
1118

1219
GRCH37 = "GRCh37"
1320
GRCH38 = "GRCh38"
14-
21+
1522

1623
class UscsAssemblyBuild(StrEnum):
17-
"""Supported USCS assembly builds"""
18-
19-
HG38 = "hg38"
20-
HG19 = "hg19"
24+
"""Supported USCS assembly builds"""
25+
26+
HG38 = "hg38"
27+
HG19 = "hg19"
2128

2229

2330
GenomicSequence = Annotated[
@@ -34,26 +41,29 @@ def _normalize_chromosome_name(chromosome_name: str) -> str:
3441
:param chromosome_name: The name of the chromosome to normalize, following the rules stated above.
3542
:return: The chromosome name, stripped of it's 'chr' prefix if it was added
3643
"""
37-
error_message = "Invalid chromosome. Must be 1–22, 'X,' or 'Y,' with optional 'chr' prefix."
44+
error_message = (
45+
"Invalid chromosome. Must be 1-22, 'X,' or 'Y,' with optional 'chr' prefix."
46+
)
3847

3948
# strip the 'chr' prefix if it was included
40-
chromosome_name = chromosome_name[3:].upper() if chromosome_name.lower().startswith("chr") else chromosome_name.upper()
41-
49+
chromosome_name = (
50+
chromosome_name[3:].upper()
51+
if chromosome_name.lower().startswith("chr")
52+
else chromosome_name.upper()
53+
)
54+
4255
# chromosome name must be either an int, or "X" or "Y"
4356
try:
4457
int(chromosome_name)
45-
except:
46-
if not chromosome_name in ["X", "Y"]:
47-
raise ValueError(error_message)
48-
58+
except ValueError:
59+
if chromosome_name not in ["X", "Y"]:
60+
raise ValueError(error_message) from None
61+
4962
# if chromosome name is an int, it must be between 1-22
50-
if chromosome_name not in range(1, 23): # stop is exclusive so we need to add 1
63+
if chromosome_name not in range(1, 23): # stop is exclusive so we need to add 1
5164
raise ValueError(error_message)
52-
65+
5366
return chromosome_name
5467

5568

56-
ChromosomeName = Annotated[
57-
str,
58-
BeforeValidator(_normalize_chromosome_name)
59-
]
69+
ChromosomeName = Annotated[str, BeforeValidator(_normalize_chromosome_name)]

0 commit comments

Comments
 (0)