Skip to content

Commit c3f16ad

Browse files
committed
more tweaks
1 parent 3de0990 commit c3f16ad

15 files changed

+1742
-52
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ dev = [
4444
"pre-commit>=4.2.0",
4545
"ipykernel",
4646
"fastapi[standard]",
47+
"seqrepo-rest-service", # for generating SeqRepo-based tests fixtures
4748
]
4849

4950
[project.urls]

src/anyvlm/anyvar/base_client.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@ class AnyVarClientError(Exception):
99
"""Generic client-related exception."""
1010

1111

12+
class UnidentifiedObjectError(AnyVarClientError):
13+
"""Raise if input object lacks an ID property"""
14+
15+
1216
class BaseAnyVarClient(abc.ABC):
1317
"""Interface elements for an AnyVar client"""
1418

1519
@abc.abstractmethod
16-
def put_objects(self, objects: list[VrsVariation]) -> list[VrsVariation]:
20+
def put_objects(self, objects: list[VrsVariation]) -> None:
1721
"""Register objects with AnyVar
1822
23+
All input objects must have a populated ID field. A validation check for this is
24+
performed before any variants are registered.
25+
1926
:param objects: variation objects to register
20-
:return: completed VRS objects
2127
:raise AnyVarClientError: for errors relating to specifics of client interface
28+
:raise UnidentifiedObjectError: if *any* provided object lacks a VRS ID
2229
"""
2330

2431
@abc.abstractmethod

src/anyvlm/anyvar/http_client.py

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
"""Provide abstraction for a VLM-to-AnyVar connection."""
22

3+
import logging
4+
35
import requests
46
from anyvar.utils.types import VrsVariation
57
from ga4gh.vrs import models
68

7-
from anyvlm.anyvar.base_client import AnyVarClientError, BaseAnyVarClient
9+
from anyvlm.anyvar.base_client import (
10+
AnyVarClientError,
11+
BaseAnyVarClient,
12+
UnidentifiedObjectError,
13+
)
14+
15+
_logger = logging.getLogger(__name__)
816

917

1018
class HttpAnyVarClient(BaseAnyVarClient):
@@ -21,36 +29,35 @@ def __init__(
2129
self.hostname = hostname
2230
self.request_timeout = request_timeout
2331

24-
def put_objects(self, objects: list[VrsVariation]) -> list[VrsVariation]:
32+
def put_objects(self, objects: list[VrsVariation]) -> None:
2533
"""Register objects with AnyVar
2634
27-
This method is intentionally naive. Future improvements could include
28-
* A better way to batch requests together to mitigate HTTP latency
29-
* A smarter dispatch for reconstructing variation model instances
35+
All input objects must have a populated ID field. A validation check for this is
36+
performed before any variants are registered.
3037
3138
:param objects: variation objects to register
3239
:return: completed VRS objects
3340
:raise AnyVarClientError: if connection is unsuccessful during registration request
41+
:raise UnidentifiedObjectError: if *any* provided object lacks a VRS ID
3442
"""
35-
results = []
43+
objects_to_submit = []
3644
for vrs_object in objects:
45+
if not vrs_object.id:
46+
_logger.error("Provided variant %s has no VRS ID: %s")
47+
raise UnidentifiedObjectError
48+
objects_to_submit.append(
49+
vrs_object.model_dump(exclude_none=True, mode="json")
50+
)
51+
for vrs_object in objects_to_submit:
3752
response = requests.put(
3853
f"{self.hostname}/vrs_variation",
39-
json=vrs_object.model_dump(exclude_none=True, mode="json"),
54+
json=vrs_object,
4055
timeout=self.request_timeout,
4156
)
4257
try:
4358
response.raise_for_status()
4459
except requests.HTTPError as e:
4560
raise AnyVarClientError from e
46-
result_object = response.json()["object"]
47-
if result_object.get("type") == "Allele":
48-
results.append(models.Allele(**result_object))
49-
else:
50-
raise NotImplementedError(
51-
f"Unsupported object type: {result_object.get('type')}"
52-
)
53-
return results
5461

5562
def search_by_interval(
5663
self, accession: str, start: int, end: int

src/anyvlm/anyvar/python_client.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
"""Implement AnyVar client interface for direct Python-based access."""
22

3+
import logging
4+
35
from anyvar import AnyVar
4-
from anyvar.storage.base_storage import IncompleteVrsObjectError, Storage
6+
from anyvar.storage.base_storage import Storage
57
from anyvar.translate.translate import Translator
6-
from anyvar.utils.types import VrsVariation, recursive_identify
8+
from anyvar.utils.types import VrsVariation
9+
10+
from anyvlm.anyvar.base_client import BaseAnyVarClient, UnidentifiedObjectError
711

8-
from anyvlm.anyvar.base_client import BaseAnyVarClient
12+
_logger = logging.getLogger(__name__)
913

1014

1115
class PythonAnyVarClient(BaseAnyVarClient):
@@ -14,21 +18,20 @@ class PythonAnyVarClient(BaseAnyVarClient):
1418
def __init__(self, translator: Translator, storage: Storage) -> None: # noqa: D107
1519
self.av = AnyVar(translator, storage)
1620

17-
def put_objects(self, objects: list[VrsVariation]) -> list[VrsVariation]:
21+
def put_objects(self, objects: list[VrsVariation]) -> None:
1822
"""Register objects with AnyVar
1923
24+
All input objects must have a populated ID field. A validation check for this is
25+
performed before any variants are registered.
26+
2027
:param objects: variation objects to register
21-
:return: completed VRS objects
28+
:raise UnidentifiedObjectError: if *any* provided object lacks a VRS ID
2229
"""
23-
complete_variations = []
24-
for variation in objects:
25-
try:
26-
self.av.put_objects([variation])
27-
except IncompleteVrsObjectError:
28-
variation = recursive_identify(variation) # noqa: PLW2901
29-
self.av.put_objects([variation])
30-
complete_variations.append(variation)
31-
return complete_variations
30+
for variant in objects:
31+
if not variant.id:
32+
_logger.error("Provided variant %s has no VRS ID: %s")
33+
raise UnidentifiedObjectError
34+
self.av.put_objects(objects) # type: ignore[reportArgumentType]
3235

3336
def search_by_interval(
3437
self, accession: str, start: int, end: int

src/anyvlm/main.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Define core FastAPI app"""
22

3+
import logging
34
from collections.abc import AsyncGenerator
45
from contextlib import asynccontextmanager
56
from enum import Enum
@@ -19,6 +20,8 @@
1920
ServiceType,
2021
)
2122

23+
_logger = logging.getLogger(__name__)
24+
2225

2326
def create_anyvar_client(
2427
connection_string: str | None = None,
@@ -27,15 +30,20 @@ def create_anyvar_client(
2730
2831
If given a string for connecting to an AnyVar instance via HTTP requests, then
2932
create an HTTP-based client. Otherwise, try to use AnyVar resource factory functions
30-
for standing up a Python-based client.
33+
for standing up a Python-based client. In the latter case, see the AnyVar documentation
34+
for configuration info (i.e. environment variables)
3135
3236
:param connection_string: description of connection param
3337
:return: client instance
3438
"""
3539
if not connection_string:
3640
connection_string = get_config().anyvar_uri
3741
if connection_string.startswith("http://"):
42+
_logger.info(
43+
"Initializing HTTP-based AnyVar client under hostname %s", connection_string
44+
)
3845
return HttpAnyVarClient(connection_string)
46+
_logger.info("Initializing AnyVar instance directly")
3947
storage = create_storage()
4048
translator = create_translator()
4149
return PythonAnyVarClient(translator, storage)

0 commit comments

Comments
 (0)