Skip to content

Commit 94905c8

Browse files
committed
Merge branch 'issue-23' into issue-16
2 parents e18d081 + 581d266 commit 94905c8

22 files changed

+665
-243
lines changed

src/anyvlm/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Settings(BaseSettings):
1515
"""
1616

1717
model_config = SettingsConfigDict(
18-
env_prefix="vlm_",
18+
env_prefix="anyvlm_",
1919
env_file=".env",
2020
env_file_encoding="utf-8",
2121
extra="ignore",
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Craft a VlmResponse object from a list of CohortAlleleFrequencyStudyResults"""
2+
3+
from ga4gh.va_spec.base.core import CohortAlleleFrequencyStudyResult
4+
5+
from anyvlm.schemas.vlm import (
6+
VlmResponse,
7+
)
8+
9+
10+
def build_vlm_response_from_caf_data(
11+
caf_data: list[CohortAlleleFrequencyStudyResult],
12+
) -> VlmResponse:
13+
"""Craft a VlmResponse object from a list of CohortAlleleFrequencyStudyResults.
14+
15+
:param caf_data: A list of `CohortAlleleFrequencyStudyResult` objects that will be used to build the VlmResponse
16+
:return: A `VlmResponse` object.
17+
"""
18+
raise NotImplementedError # TODO: Implement this during/after Issue #16

src/anyvlm/functions/get_caf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ def get_caf(
2222
:param anyvlm_storage: AnyVLM Storage (CAF storage and retrieval)
2323
:param accession_id: ID for sequence to search upon
2424
:param start: start of range search
25-
:param end: end of range to search
25+
:param reference_bases: Genomic bases ('T', 'AC', etc.)
26+
:param alternate_bases: Genomic bases ('T', 'AC', etc.)
2627
:return: list of CAFs contained in search interval
2728
"""
2829
vrs_variations: list[VrsVariation] = anyvar.search_by_interval(

src/anyvlm/main.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import logging
44
from collections.abc import AsyncGenerator
55
from contextlib import asynccontextmanager
6-
from enum import Enum
76

87
from anyvar.anyvar import create_storage, create_translator
98
from fastapi import FastAPI
@@ -19,6 +18,9 @@
1918
ServiceOrganization,
2019
ServiceType,
2120
)
21+
from anyvlm.utils.types import (
22+
EndpointTag,
23+
)
2224

2325
_logger = logging.getLogger(__name__)
2426

@@ -79,18 +81,11 @@ async def lifespan(app: FastAPI) -> AsyncGenerator:
7981
)
8082

8183

82-
class _Tag(str, Enum):
83-
"""Define tag names for endpoints."""
84-
85-
META = "Meta"
86-
SEARCH = "Search"
87-
88-
8984
@app.get(
9085
"/service-info",
9186
summary="Get basic service information",
9287
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/)",
93-
tags=[_Tag.META],
88+
tags=[EndpointTag.META],
9489
)
9590
def service_info() -> ServiceInfo:
9691
"""Provide service info per GA4GH Service Info spec"""

src/anyvlm/restapi/vlm.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,25 @@
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+
from ga4gh.va_spec.base.core import CohortAlleleFrequencyStudyResult
8+
9+
from anyvlm.anyvar.base_client import BaseAnyVarClient
10+
from anyvlm.functions.build_vlm_response import build_vlm_response_from_caf_data
11+
from anyvlm.functions.get_caf import get_caf
12+
from anyvlm.main import app
13+
from anyvlm.schemas.vlm import (
14+
VlmResponse,
15+
)
16+
from anyvlm.utils.types import (
17+
ChromosomeName,
18+
EndpointTag,
19+
GrcAssemblyId,
20+
NucleotideSequence,
21+
UcscAssemblyBuild,
22+
)
423

524

625
def ingest_vcf(vcf_path: Path) -> None:
@@ -9,3 +28,34 @@ def ingest_vcf(vcf_path: Path) -> None:
928
:param vcf_path: VCF file location
1029
"""
1130
raise NotImplementedError
31+
32+
33+
@app.get(
34+
"/variant_counts",
35+
summary="Provides allele counts of a single sequence variant, broken down by zygosity",
36+
description="Search for a single sequence variant and receive allele counts by zygosity, in accordance with the Variant-Level Matching protocol",
37+
tags=[EndpointTag.SEARCH],
38+
)
39+
# ruff: noqa: D103, N803 (allow camelCase args and don't require docstrings)
40+
def variant_counts(
41+
request: Request,
42+
assemblyId: Annotated[
43+
GrcAssemblyId | UcscAssemblyBuild,
44+
Query(..., description="Genome reference assembly"),
45+
],
46+
referenceName: Annotated[
47+
ChromosomeName, Query(..., description="Chromosome with optional 'chr' prefix")
48+
],
49+
start: Annotated[int, Query(..., description="Variant position")],
50+
referenceBases: Annotated[
51+
NucleotideSequence, Query(..., description="Genomic bases ('T', 'AC', etc.)")
52+
],
53+
alternateBases: Annotated[
54+
NucleotideSequence, Query(..., description="Genomic bases ('T', 'AC', etc.)")
55+
],
56+
) -> VlmResponse:
57+
anyvar_client: BaseAnyVarClient = request.app.state.anyvar_client
58+
caf_data: list[CohortAlleleFrequencyStudyResult] = get_caf(
59+
anyvar_client, assemblyId, referenceName, start, referenceBases, alternateBases
60+
)
61+
return build_vlm_response_from_caf_data(caf_data)

src/anyvlm/schemas/vlm.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,154 @@
11
"""Schemas relating to VLM API."""
2+
3+
from typing import ClassVar, Literal, Self
4+
5+
from pydantic import BaseModel, ConfigDict, Field, model_validator
6+
7+
from anyvlm.utils.types import Zygosity
8+
9+
# ruff: noqa: N815 (allows camelCase vars instead of snake_case to align with expected VLM protocol response)
10+
11+
RESULT_ENTITY_TYPE = "genomicVariant"
12+
13+
14+
class HandoverType(BaseModel):
15+
"""The type of handover the parent `BeaconHandover` represents."""
16+
17+
id: str = Field(
18+
default="gregor", description="Node-specific identifier"
19+
) # TODO: enable configuration of this field. See Issue #27.
20+
label: str = Field(
21+
default="GREGoR AnVIL browser", description="Node-specific label"
22+
) # TODO: enable configuration of this field. See Issue #27.
23+
24+
25+
class BeaconHandover(BaseModel):
26+
"""Describes how users can get more information about the results provided in the parent `VlmResponse`"""
27+
28+
handoverType: HandoverType = HandoverType()
29+
url: str = Field(
30+
default="https://anvil.terra.bio/#workspaces?filter=GREGoR", # TODO: enable configuration of this field. See Issue #27.
31+
description="A url which directs users to more detailed information about the results tabulated by the API (ideally human-readable)",
32+
)
33+
34+
35+
class ReturnedSchema(BaseModel):
36+
"""Fixed [Beacon Schema](https://github.com/ga4gh-beacon/beacon-v2/blob/c6558bf2e6494df3905f7b2df66e903dfe509500/framework/json/common/beaconCommonComponents.json#L241)"""
37+
38+
entityType: str = Field(
39+
default=RESULT_ENTITY_TYPE,
40+
description=f"The type of entity this response describes. Must always be set to '{RESULT_ENTITY_TYPE}'",
41+
)
42+
schema_: str = Field(
43+
default="ga4gh-beacon-variant-v2.0.0",
44+
# Alias is required because 'schema' is reserved by Pydantic's BaseModel class,
45+
# But VLM expects a field named 'schema'
46+
alias="schema",
47+
)
48+
49+
model_config = ConfigDict(populate_by_name=True)
50+
51+
52+
class Meta(BaseModel):
53+
"""Relevant metadata about the results provided in the parent `VlmResponse`"""
54+
55+
apiVersion: str = Field(
56+
default="v1.0",
57+
description="The version of the VLM API that this response conforms to",
58+
)
59+
beaconId: str = Field(
60+
default="org.gregor.beacon", # TODO: enable configuration of this field. See Issue #27.
61+
description="""
62+
The Id of a Beacon. Usually a reversed domain string, but any URI is acceptable. The purpose of this attribute is,
63+
in the context of a Beacon network, to disambiguate responses coming from different Beacons. See the beacon documentation
64+
[here](https://github.com/ga4gh-beacon/beacon-v2/blob/c6558bf2e6494df3905f7b2df66e903dfe509500/framework/src/common/beaconCommonComponents.yaml#L26)
65+
""",
66+
)
67+
returnedSchemas: list[ReturnedSchema] = [ReturnedSchema()]
68+
69+
70+
class ResponseSummary(BaseModel):
71+
"""A high-level summary of the results provided in the parent `VlmResponse"""
72+
73+
exists: bool = Field(
74+
..., description="Indicates whether the response contains any results."
75+
)
76+
numTotalResults: int = Field(
77+
..., description="The total number of results found for the given query"
78+
)
79+
80+
81+
class ResultSet(BaseModel):
82+
"""A set of cohort allele frequency results. The zygosity of the ResultSet is identified in the `id` field"""
83+
84+
exists: Literal[True] = Field(
85+
default=True,
86+
description="Indicates whether this ResultSet exists. This must always be `True`, even if `resultsCount` = `0`",
87+
)
88+
id: str = Field(
89+
...,
90+
description="id should be constructed of the `HandoverType.id` + the ResultSet's zygosity. See `validate_resultset_ids` validator in `VlmResponse` class.",
91+
examples=["Geno2MP Homozygous", "MyGene2 Heterozygous"],
92+
)
93+
results: list = Field(
94+
default=[],
95+
min_length=0,
96+
max_length=0,
97+
description="This must always be set to an empty array",
98+
)
99+
resultsCount: int = Field(
100+
..., description="A count for the zygosity indicated by the ResultSet's `id`"
101+
)
102+
setType: str = Field(
103+
default=RESULT_ENTITY_TYPE,
104+
description=f"The type of entity relevant to these results. Must always be set to '{RESULT_ENTITY_TYPE}'",
105+
)
106+
107+
108+
class ResponseField(BaseModel):
109+
"""A list of ResultSets"""
110+
111+
resultSets: list[ResultSet] = Field(
112+
..., description="A list of ResultSets for the given query."
113+
)
114+
115+
116+
class VlmResponse(BaseModel):
117+
"""Define response structure for the variant_counts endpoint."""
118+
119+
beaconHandovers: list[BeaconHandover] = [BeaconHandover()]
120+
meta: Meta = Meta()
121+
responseSummary: ResponseSummary
122+
response: ResponseField
123+
124+
resultset_id_error_message_base: ClassVar[str] = (
125+
"Invalid ResultSet id - ids must be in form '<node_id> <zygosity>'"
126+
)
127+
128+
@model_validator(mode="after")
129+
def validate_resultset_ids(self) -> Self:
130+
"""Ensure each ResultSet.id is correctly constructed."""
131+
handover_ids: list[str] = [
132+
beaconHandover.handoverType.id for beaconHandover in self.beaconHandovers
133+
]
134+
135+
for result_set in self.response.resultSets:
136+
node_id, zygosity = None, None
137+
try:
138+
node_id, zygosity = result_set.id.split(" ")
139+
except ValueError as e:
140+
error_message = f"{self.resultset_id_error_message_base}, but provided id of {result_set.id} contains invalid formatting"
141+
raise ValueError(error_message) from e
142+
143+
if node_id not in handover_ids:
144+
error_message = f"{self.resultset_id_error_message_base}, but provided node_id of {node_id} does not match any `handoverType.id` provided in `self.beaconHandovers`"
145+
raise ValueError(error_message)
146+
147+
try:
148+
Zygosity(zygosity)
149+
except ValueError as e:
150+
valid_zygosity_values = {zygosity.value for zygosity in Zygosity}
151+
error_message = f"{self.resultset_id_error_message_base}, but provided zygosity of {zygosity} is not found in allowable value set of: {', '.join(valid_zygosity_values)}"
152+
raise ValueError(error_message) from e
153+
154+
return self

src/anyvlm/utils/types.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
"""Provide helpful type definitions, references, and type-based operations."""
22

3-
from pydantic import BaseModel
3+
from enum import Enum, StrEnum
4+
from typing import Annotated
5+
6+
from pydantic import BaseModel, BeforeValidator, StringConstraints
47

58

69
class AncillaryResults(BaseModel):
@@ -15,3 +18,67 @@ class QualityMeasures(BaseModel):
1518
"""Define model for Quality Measures"""
1619

1720
qcFilters: list[str] | None = None # noqa: N815
21+
22+
23+
class EndpointTag(str, Enum):
24+
"""Define tag names for endpoints."""
25+
26+
META = "Meta"
27+
SEARCH = "Search"
28+
29+
30+
class GrcAssemblyId(StrEnum):
31+
"""Supported GRC assembly identifiers"""
32+
33+
GRCH37 = "GRCh37"
34+
GRCH38 = "GRCh38"
35+
36+
37+
class UcscAssemblyBuild(StrEnum):
38+
"""Supported UCSC assembly builds"""
39+
40+
HG38 = "hg38"
41+
HG19 = "hg19"
42+
43+
44+
NucleotideSequence = Annotated[
45+
str,
46+
BeforeValidator(str.upper),
47+
StringConstraints(pattern=r"^[ACGTURYKMSWBDHVN.-]*$"),
48+
]
49+
50+
51+
def _normalize_chromosome_name(chromosome_name: str) -> str:
52+
"""Normalize a chromosome name. Input must be a string consisting of either a number between 1-22,
53+
or one of the values 'X', 'Y', or 'MT'; optionally prefixed with 'chr'.
54+
55+
:param chromosome_name: The name of the chromosome to normalize, following the rules stated above.
56+
:return: The chromosome name, stripped of it's 'chr' prefix if it was added
57+
"""
58+
chromosome_name = chromosome_name.upper().removeprefix("CHR")
59+
60+
min_chromosome_number = 1
61+
max_chromosome_number = 22
62+
63+
if chromosome_name in {"X", "Y", "MT"} or (
64+
chromosome_name.isdigit()
65+
and min_chromosome_number <= int(chromosome_name) <= max_chromosome_number
66+
):
67+
return chromosome_name
68+
69+
raise ValueError(
70+
"Invalid chromosome. Must be either a number between 1-22, or "
71+
"'one of the values 'X', 'Y', or 'MT'; optionally prefixed with 'chr'."
72+
)
73+
74+
75+
ChromosomeName = Annotated[str, BeforeValidator(_normalize_chromosome_name)]
76+
77+
78+
class Zygosity(StrEnum):
79+
"""Allowable zygosity values as defined by the VLM protocol"""
80+
81+
HOMOZYGOUS = "Homozygous"
82+
HETEROZYGOUS = "Heterozygous"
83+
HEMIZYGOUS = "Hemizygous"
84+
UNKNOWN = "Unknown Zygosity"

tests/unit/anyvar/cassettes/test_http_client/test_put_objects.yaml renamed to tests/unit/anyvar/cassettes/test_clients/test_put_objects[anyvar_http_client].yaml

File renamed without changes.

tests/unit/anyvar/cassettes/test_http_client/test_search_by_interval.yaml renamed to tests/unit/anyvar/cassettes/test_clients/test_search_by_interval[anyvar_http_client].yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ interactions:
66
uri: http://localhost:8000/search?accession=ga4gh:SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5&start=2781760&end=2781760
77
response:
88
body:
9-
string: '{"variations":[{"id":"ga4gh:VA.IM4QyU9D2kTJzeftUBBD4Vcd1peq0dn1","type":"Allele","digest":"IM4QyU9D2kTJzeftUBBD4Vcd1peq0dn1","location":{"id":"ga4gh:SL.sWfeTXwGUkfIuYRAkiFGPjkSk_mIDuXG","type":"SequenceLocation","digest":"sWfeTXwGUkfIuYRAkiFGPjkSk_mIDuXG","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781762},"state":{"type":"LiteralSequenceExpression","sequence":"CA"}},{"id":"ga4gh:VA.9VDxL0stMBOZwcTKw3yb3UoWQkpaI9OD","type":"Allele","digest":"9VDxL0stMBOZwcTKw3yb3UoWQkpaI9OD","location":{"id":"ga4gh:SL.sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","type":"SequenceLocation","digest":"sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781761},"state":{"type":"LiteralSequenceExpression","sequence":"A"}},{"id":"ga4gh:VA.xbX035HgURWIUAjn6x3cS26jafP8Q_bk","type":"Allele","digest":"xbX035HgURWIUAjn6x3cS26jafP8Q_bk","location":{"id":"ga4gh:SL.sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","type":"SequenceLocation","digest":"sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781761},"state":{"type":"LiteralSequenceExpression","sequence":"C"}}]}'
9+
string: '{"variations":[{"id":"ga4gh:VA.IM4QyU9D2kTJzeftUBBD4Vcd1peq0dn1","type":"Allele","digest":"IM4QyU9D2kTJzeftUBBD4Vcd1peq0dn1","location":{"id":"ga4gh:SL.sWfeTXwGUkfIuYRAkiFGPjkSk_mIDuXG","type":"SequenceLocation","digest":"sWfeTXwGUkfIuYRAkiFGPjkSk_mIDuXG","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781762},"state":{"type":"LiteralSequenceExpression","sequence":"CA"}},{"id":"ga4gh:VA.xbX035HgURWIUAjn6x3cS26jafP8Q_bk","type":"Allele","digest":"xbX035HgURWIUAjn6x3cS26jafP8Q_bk","location":{"id":"ga4gh:SL.sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","type":"SequenceLocation","digest":"sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781761},"state":{"type":"LiteralSequenceExpression","sequence":"C"}},{"id":"ga4gh:VA.9VDxL0stMBOZwcTKw3yb3UoWQkpaI9OD","type":"Allele","digest":"9VDxL0stMBOZwcTKw3yb3UoWQkpaI9OD","location":{"id":"ga4gh:SL.sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","type":"SequenceLocation","digest":"sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781761},"state":{"type":"LiteralSequenceExpression","sequence":"A"}}]}'
1010
headers: {}
1111
status:
1212
code: 200
@@ -18,7 +18,7 @@ interactions:
1818
uri: http://localhost:8000/search?accession=ga4gh:SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5&start=2781760&end=2781768
1919
response:
2020
body:
21-
string: '{"variations":[{"id":"ga4gh:VA.IM4QyU9D2kTJzeftUBBD4Vcd1peq0dn1","type":"Allele","digest":"IM4QyU9D2kTJzeftUBBD4Vcd1peq0dn1","location":{"id":"ga4gh:SL.sWfeTXwGUkfIuYRAkiFGPjkSk_mIDuXG","type":"SequenceLocation","digest":"sWfeTXwGUkfIuYRAkiFGPjkSk_mIDuXG","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781762},"state":{"type":"LiteralSequenceExpression","sequence":"CA"}},{"id":"ga4gh:VA.9VDxL0stMBOZwcTKw3yb3UoWQkpaI9OD","type":"Allele","digest":"9VDxL0stMBOZwcTKw3yb3UoWQkpaI9OD","location":{"id":"ga4gh:SL.sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","type":"SequenceLocation","digest":"sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781761},"state":{"type":"LiteralSequenceExpression","sequence":"A"}},{"id":"ga4gh:VA.xbX035HgURWIUAjn6x3cS26jafP8Q_bk","type":"Allele","digest":"xbX035HgURWIUAjn6x3cS26jafP8Q_bk","location":{"id":"ga4gh:SL.sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","type":"SequenceLocation","digest":"sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781761},"state":{"type":"LiteralSequenceExpression","sequence":"C"}},{"id":"ga4gh:VA.yi7A2l0uIUMaInQaJnHU_B2Cf_OuZRJg","type":"Allele","digest":"yi7A2l0uIUMaInQaJnHU_B2Cf_OuZRJg","location":{"id":"ga4gh:SL.JsFGLKlUDocinf7oWTXAvVT2WOso7R9u","type":"SequenceLocation","digest":"JsFGLKlUDocinf7oWTXAvVT2WOso7R9u","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781761,"end":2781785},"state":{"type":"ReferenceLengthExpression","length":23,"sequence":"AAAAAAAAAAAAAAAAAAAAAAA","repeatSubunitLength":1}}]}'
21+
string: '{"variations":[{"id":"ga4gh:VA.IM4QyU9D2kTJzeftUBBD4Vcd1peq0dn1","type":"Allele","digest":"IM4QyU9D2kTJzeftUBBD4Vcd1peq0dn1","location":{"id":"ga4gh:SL.sWfeTXwGUkfIuYRAkiFGPjkSk_mIDuXG","type":"SequenceLocation","digest":"sWfeTXwGUkfIuYRAkiFGPjkSk_mIDuXG","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781762},"state":{"type":"LiteralSequenceExpression","sequence":"CA"}},{"id":"ga4gh:VA.xbX035HgURWIUAjn6x3cS26jafP8Q_bk","type":"Allele","digest":"xbX035HgURWIUAjn6x3cS26jafP8Q_bk","location":{"id":"ga4gh:SL.sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","type":"SequenceLocation","digest":"sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781761},"state":{"type":"LiteralSequenceExpression","sequence":"C"}},{"id":"ga4gh:VA.9VDxL0stMBOZwcTKw3yb3UoWQkpaI9OD","type":"Allele","digest":"9VDxL0stMBOZwcTKw3yb3UoWQkpaI9OD","location":{"id":"ga4gh:SL.sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","type":"SequenceLocation","digest":"sYiBcbbgF-1CANNCTfQ6zwZOU0iHhymR","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781760,"end":2781761},"state":{"type":"LiteralSequenceExpression","sequence":"A"}},{"id":"ga4gh:VA.yi7A2l0uIUMaInQaJnHU_B2Cf_OuZRJg","type":"Allele","digest":"yi7A2l0uIUMaInQaJnHU_B2Cf_OuZRJg","location":{"id":"ga4gh:SL.JsFGLKlUDocinf7oWTXAvVT2WOso7R9u","type":"SequenceLocation","digest":"JsFGLKlUDocinf7oWTXAvVT2WOso7R9u","sequenceReference":{"type":"SequenceReference","refgetAccession":"SQ.8_liLu1aycC0tPQPFmUaGXJLDs5SbPZ5"},"start":2781761,"end":2781785},"state":{"type":"ReferenceLengthExpression","length":23,"sequence":"AAAAAAAAAAAAAAAAAAAAAAA","repeatSubunitLength":1}}]}'
2222
headers: {}
2323
status:
2424
code: 200

tests/unit/anyvar/cassettes/test_http_client/test_search_by_interval_not_found.yaml renamed to tests/unit/anyvar/cassettes/test_clients/test_search_by_interval_not_found[anyvar_http_client].yaml

File renamed without changes.

0 commit comments

Comments
 (0)