diff --git a/dotty/main.py b/dotty/main.py index 116a9ad..f8563e7 100644 --- a/dotty/main.py +++ b/dotty/main.py @@ -92,11 +92,13 @@ class Spdi(pydantic.BaseModel): alternate_inserted: str -class Result(pydantic.BaseModel): +class SpdiResult(pydantic.BaseModel): """The result of the query.""" + #: The indicator if the query was successful. + success: bool #: The actual payload / SPDI representation of the variant. - spdi: Spdi + value: Spdi | None class ExonAlignment(pydantic.BaseModel): @@ -186,13 +188,13 @@ class TranscriptResult(pydantic.BaseModel): transcripts: list[Transcript] -@app.get("/api/v1/to-spdi", response_model=Result) -async def to_spdi(q: str, assembly: Assembly = Assembly.GRCH38) -> Result: +@app.get("/api/v1/to-spdi", response_model=SpdiResult) +async def to_spdi(q: str, assembly: Assembly = Assembly.GRCH38) -> SpdiResult: """Resolve the given HGVS variant to SPDI representation.""" try: parsed_var = driver.parser.parse(q) except hgvs.exceptions.HGVSParseError: - raise HTTPException(status_code=400, detail="Invalid HGVS description") + return SpdiResult(success=False, value=None) if parsed_var.type == "c": var_g = driver.assembly_mappers[assembly].c_to_g(parsed_var) @@ -207,14 +209,15 @@ async def to_spdi(q: str, assembly: Assembly = Assembly.GRCH38) -> Result: contig, pos, reference, alternative, type_ = driver.babelfishes[assembly].hgvs_to_vcf(var_g) - return Result( - spdi=Spdi( + return SpdiResult( + success=True, + value=Spdi( assembly=assembly.value, contig=contig, pos=pos, reference_deleted=reference, alternate_inserted=alternative, - ) + ), ) diff --git a/tests/test_main.py b/tests/test_main.py index fad529c..ce45d06 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -2,6 +2,7 @@ import typing from unittest.mock import Mock +import hgvs.exceptions from _pytest.monkeypatch import MonkeyPatch from fastapi.testclient import TestClient from pytest_snapshot.plugin import Snapshot @@ -85,13 +86,14 @@ def test_to_spdi_c(test_client: TestClient, monkeypatch: MonkeyPatch): response = test_client.get("/api/v1/to-spdi?q=NM_000059.3:c.274G>A") assert response.status_code == 200 expected = { - "spdi": { + "success": True, + "value": { "alternate_inserted": "C", "contig": "chr1", "pos": 100, "reference_deleted": "A", "assembly": "GRCh38", - } + }, } assert response.json() == expected @@ -101,13 +103,14 @@ def test_to_spdi_n(test_client: TestClient, monkeypatch: MonkeyPatch): response = test_client.get("/api/v1/to-spdi?q=NM_000059.3:n.274G>A") assert response.status_code == 200 expected = { - "spdi": { + "success": True, + "value": { "alternate_inserted": "C", "contig": "chr1", "pos": 100, "reference_deleted": "A", "assembly": "GRCh38", - } + }, } assert response.json() == expected @@ -117,13 +120,14 @@ def test_to_spdi_g_37(test_client: TestClient, monkeypatch: MonkeyPatch): response = test_client.get("/api/v1/to-spdi?q=NC_000017.10:g.41197699T>C") assert response.status_code == 200 expected = { - "spdi": { + "success": True, + "value": { "alternate_inserted": "C", "contig": "chr1", "pos": 100, "reference_deleted": "A", "assembly": "GRCh37", - } + }, } assert response.json() == expected @@ -133,13 +137,30 @@ def test_to_spdi_g_38(test_client: TestClient, monkeypatch: MonkeyPatch): response = test_client.get("/api/v1/to-spdi?q=NC_000017.11:g.43045682T>C") assert response.status_code == 200 expected = { - "spdi": { + "success": True, + "value": { "alternate_inserted": "C", "contig": "chr1", "pos": 100, "reference_deleted": "A", "assembly": "GRCh38", - } + }, + } + assert response.json() == expected + + +def test_to_spdi_invalid(test_client: TestClient, monkeypatch: MonkeyPatch): + mock_driver = Mock() + mock_driver.parser = Mock() + mock_driver.parser.parse = Mock() + mock_driver.parser.parse.side_effect = hgvs.exceptions.HGVSParseError + monkeypatch.setattr(dotty_main, "driver", mock_driver) + + response = test_client.get("/api/v1/to-spdi?q=BRCA1") + assert response.status_code == 200 + expected = { + "success": False, + "value": None, } assert response.json() == expected