Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ebextensions/01_download_data.config
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ container_commands:
test: test -f "/usr/local/share/seqrepo.tar.gz"
command: "rm /usr/local/share/seqrepo.tar.gz"

04_install_package:
05_install_package:
leader_only: true
command: |
set -euo pipefail
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ A set of Docker Compose resources are provided as part of the AnyVLM project. Se
Given an available AnyVLM node, submit a VCF which contains allele frequency data:

```bash
curl -X POST "http://localhost:8080/ingest_vcf?assembly=grch38" \
curl -X POST "http://localhost:8080/anyvlm/ingest_vcf?assembly=grch38" \
-F "file=@/path/to/variants.vcf.gz"
```

Then, submit a query for allele frequency

```bash
curl "http://localhost:8080/variant_counts?assemblyId=GRCh38&referenceName=7&start=140714556&referenceBases=A&alternateBases=T"
curl "http://localhost:8080/anyvlm/variant_counts?assemblyId=GRCh38&referenceName=7&start=140714556&referenceBases=A&alternateBases=T"
```

A successful query returns a response like the following:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Given a VCF describing cohort-level allele frequency, submit a ``POST`` request

.. code-block:: console

% curl -X POST "http://localhost:8080/ingest_vcf?assembly=grch38" \
% curl -X POST "http://localhost:8080/anyvlm/ingest_vcf?assembly=grch38" \
-F "file=@/path/to/variants.vcf.gz"

VCF Requirements
Expand Down Expand Up @@ -42,7 +42,7 @@ Issue a ``GET`` request to ``/variant_counts`` with arguments for reference sequ

.. code-block:: console

% curl "http://localhost:8080/variant_counts?assemblyId=GRCh38&referenceName=22&start=10510105&referenceBases=T&alternateBases=A"
% curl "http://localhost:8080/anyvlm/variant_counts?assemblyId=GRCh38&referenceName=22&start=10510105&referenceBases=T&alternateBases=A"

Parameters
----------
Expand Down
9 changes: 6 additions & 3 deletions src/anyvlm/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,14 @@ async def lifespan(app: FastAPI) -> AsyncGenerator:
app.state.anyvlm_storage.close()


API_PREFIX = "/anyvlm"

app = FastAPI(
title="AnyVLM",
description=SERVICE_DESCRIPTION,
version=__version__,
docs_url="/",
docs_url=API_PREFIX,
openapi_url=f"{API_PREFIX}/openapi.json",
license={
"name": "Apache 2.0",
"url": "https://github.com/genomicmedlab/anyvlm/blob/main/LICENSE",
Expand All @@ -161,7 +164,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator:
swagger_ui_parameters={"tryItOutEnabled": True},
lifespan=lifespan,
)
app.include_router(vlm_router)
app.include_router(vlm_router, prefix=API_PREFIX)


@app.exception_handler(RequestValidationError)
Expand All @@ -188,7 +191,7 @@ async def validation_exception_handler(


@app.get(
"/service-info",
f"{API_PREFIX}/service-info",
summary="Get basic service information",
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/)",
tags=[EndpointTag.META],
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_restapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def restapi_client():


def test_service_info(restapi_client: TestClient, test_data_dir: Path):
response = restapi_client.get("/service-info")
response = restapi_client.get("/anyvlm/service-info")
response.raise_for_status()

with (test_data_dir / "ga4gh-service-info" / "service-info.yaml").open() as f:
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_variant_counts_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"referenceBases": TEST_VARIANT.ref,
"alternateBases": TEST_VARIANT.alt,
}
ENDPOINT = "/variant_counts"
ENDPOINT = "/anyvlm/variant_counts"


@pytest.fixture(scope="session")
Expand Down
27 changes: 14 additions & 13 deletions tests/unit/test_vcf_upload_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# Constants for testing
MAX_FILE_SIZE = 5 * 1024 * 1024 * 1024 # 5GB
UPLOAD_CHUNK_SIZE = 1024 * 1024 # 1MB
ENDPOINT = "/anyvlm/ingest_vcf"


@pytest.fixture(scope="module")
Expand Down Expand Up @@ -160,14 +161,14 @@ class TestIngestVcfEndpoint:

def test_endpoint_exists(self, client: TestClient):
"""Test that the endpoint exists and accepts POST."""
response = client.post("/ingest_vcf")
response = client.post(ENDPOINT)
# Should not be 404
assert response.status_code != 404

def test_missing_file_parameter(self, client: TestClient):
"""Test request without file parameter."""
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
)
assert response.status_code == 422 # Unprocessable Entity
Expand All @@ -177,7 +178,7 @@ def test_missing_assembly_parameter(self, client: TestClient, valid_vcf_gz: Path
"""Test request without assembly parameter."""
with valid_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post("/ingest_vcf", files=files)
response = client.post(ENDPOINT, files=files)

assert response.status_code == 422
assert (
Expand All @@ -189,7 +190,7 @@ def test_invalid_assembly_value(self, client: TestClient, valid_vcf_gz: Path):
with valid_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh99"}, # Invalid
files=files,
)
Expand All @@ -202,7 +203,7 @@ def test_invalid_file_extension(self, client: TestClient, valid_vcf_gz: Path):
# Use .vcf extension (should be .vcf.gz)
files = {"file": ("test.vcf", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
files=files,
)
Expand All @@ -219,7 +220,7 @@ def test_not_gzipped_file(self, client: TestClient):
files = {"file": ("test.vcf.gz", io.BytesIO(content), "application/gzip")}

response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
files=files,
)
Expand All @@ -234,7 +235,7 @@ def test_not_a_vcf_file(self, client: TestClient, not_vcf_gz: Path):
with not_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
files=files,
)
Expand All @@ -251,7 +252,7 @@ def test_vcf_missing_required_fields(
with missing_fields_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
files=files,
)
Expand All @@ -275,7 +276,7 @@ def test_successful_upload_and_ingestion(
with valid_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
files=files,
)
Expand Down Expand Up @@ -312,7 +313,7 @@ def test_ingestion_failure_propagates(
with valid_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
files=files,
)
Expand All @@ -330,7 +331,7 @@ def test_temp_file_cleanup_on_success(self, client: TestClient, valid_vcf_gz: Pa
with valid_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
files=files,
)
Expand All @@ -350,7 +351,7 @@ def test_temp_file_cleanup_on_error(self, client: TestClient, valid_vcf_gz: Path
with valid_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh38"},
files=files,
)
Expand All @@ -372,7 +373,7 @@ def test_assembly_grch37_parameter(self, client: TestClient, valid_vcf_gz: Path)
with valid_vcf_gz.open("rb") as f:
files = {"file": ("test.vcf.gz", f, "application/gzip")}
response = client.post(
"/ingest_vcf",
ENDPOINT,
params={"assembly": "GRCh37"},
files=files,
)
Expand Down
Loading