Skip to content

Commit 922bcb3

Browse files
committed
stash
1 parent 5594d03 commit 922bcb3

File tree

3 files changed

+118
-1
lines changed

3 files changed

+118
-1
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ dependencies = [
2626
"anyio",
2727
"python-dotenv",
2828
"pydantic-settings",
29+
"requests",
2930
]
3031
dynamic = ["version"]
3132

src/vlm/anyvar/base_client.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66

77
from vlm.schemas.domain import AlleleFrequencyAnnotation
88

9+
# define constant to use as AnyVar annotation type
10+
AF_ANNOTATION_TYPE = "cohort_allele_frequency"
11+
12+
13+
class AmbiguousAnnotationError(Exception):
14+
"""Raise if multiple candidate annotations exist on a variation"""
15+
916

1017
class BaseAnyVarClient(abc.ABC):
1118
"""Interface elements for an AnyVar client"""
@@ -21,7 +28,6 @@ def put_objects(self, objects: list[VrsObject]) -> None:
2128
def put_af_annotation(self, key: str, af: AlleleFrequencyAnnotation) -> None:
2229
"""Add an allele frequency annotation to a variation
2330
24-
2531
:param key: VRS ID for variation being annotated
2632
:param af: frequency data for for annotation
2733
"""
@@ -38,6 +44,15 @@ def search_by_interval(
3844
:return: list of matching variant objects
3945
"""
4046

47+
@abc.abstractmethod
48+
def get_af_annotation(self, key: str) -> AlleleFrequencyAnnotation | None:
49+
"""Get AF annotation for a key (object ID)
50+
51+
:param key: object ID (presumably VRS ID)
52+
:return: AF object if available, `None` otherwise
53+
:raise KeyError: if object with given ID doesn't exist
54+
"""
55+
4156
@abc.abstractmethod
4257
def close(self) -> None:
4358
"""Clean up AnyVar connection."""

src/vlm/anyvar/http_client.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""Provide abstraction for a VLM-to-AnyVar connection."""
2+
3+
import abc
4+
from http import HTTPStatus
5+
6+
import requests
7+
from anyvar.utils.types import VrsObject
8+
9+
from vlm.anyvar.base_client import AF_ANNOTATION_TYPE, AmbiguousAnnotationError
10+
from vlm.schemas.domain import AlleleFrequencyAnnotation
11+
12+
13+
class HttpAnyVarClient(abc.ABC):
14+
"""AnyVar HTTP-based client"""
15+
16+
def __init__(
17+
self, hostname: str = "http://localhost:8000", request_timeout: int = 30
18+
) -> None:
19+
"""Initialize client instance
20+
21+
:param hostname: service API root
22+
:param request_timeout: timeout value, in seconds, for HTTP requests
23+
"""
24+
self.hostname = hostname
25+
self.request_timeout = request_timeout
26+
27+
def put_objects(self, objects: list[VrsObject]) -> list[VrsObject]:
28+
"""Register objects with AnyVar
29+
30+
:param objects: variation objects to register
31+
:return: completed VRS objects
32+
"""
33+
results = []
34+
url = f"{self.hostname}/vrs_variation"
35+
for vrs_object in objects:
36+
response = requests.put(
37+
url,
38+
json=vrs_object.model_dump(exclude_none=True, mode="json"),
39+
timeout=self.request_timeout,
40+
)
41+
response.raise_for_status()
42+
results.append(response.json()["object"])
43+
return results
44+
45+
def put_af_annotation(self, key: str, af: AlleleFrequencyAnnotation) -> None:
46+
"""Add an allele frequency annotation to a variation
47+
48+
:param key: VRS ID for variation being annotated
49+
:param af: frequency data for for annotation
50+
"""
51+
response = requests.post(
52+
f"{self.hostname}/variation/{key}/annotations",
53+
json={
54+
"annotation_type": AF_ANNOTATION_TYPE,
55+
"annotation_value": af.model_dump(mode="json", exclude_none=True),
56+
},
57+
timeout=self.request_timeout,
58+
)
59+
response.raise_for_status()
60+
61+
@abc.abstractmethod
62+
def search_by_interval(
63+
self, accession: str, start: int, end: int
64+
) -> list[VrsObject]:
65+
"""Get all variation IDs located within the specified range
66+
67+
:param accession: sequence accession
68+
:param start: start position for genomic region
69+
:param end: end position for genomic region
70+
:return: list of matching variant objects
71+
"""
72+
73+
def get_af_annotation(self, key: str) -> AlleleFrequencyAnnotation | None:
74+
"""Get AF annotation for a key (object ID)
75+
76+
:param key: object ID (presumably VRS ID)
77+
:return: AF object if available, `None` otherwise
78+
:raise KeyError: if object with given ID doesn't exist
79+
"""
80+
response = requests.get(
81+
f"{self.hostname}/variation/{key}/annotations/{AF_ANNOTATION_TYPE}",
82+
timeout=self.request_timeout,
83+
)
84+
try:
85+
response.raise_for_status()
86+
except requests.HTTPError as e:
87+
if response.status_code == HTTPStatus.NOT_FOUND:
88+
raise KeyError from e
89+
raise
90+
data = response.json()
91+
if len(data["annotations"]) == 0:
92+
return None
93+
if len(data["annotations"]) > 1:
94+
raise AmbiguousAnnotationError
95+
return AlleleFrequencyAnnotation(**data["annotations"][0]["annotation_value"])
96+
97+
def close(self) -> None: # noqa: B027
98+
"""Clean up AnyVar connection.
99+
100+
This is a no-op for this class.
101+
"""

0 commit comments

Comments
 (0)