import json
import tempfile
from pathlib import Path
import pytest
import ferro_hgvs
SEQUENCE = "GGATTACAGGCATTAGCCTGAGGATTACAGGCATTAGCCT"
@pytest.fixture(scope="module")
def normalizer():
reference = {
"transcripts": [
{
"id": "TEMPLATE",
"gene_symbol": "T",
"strand": "+",
"sequence": SEQUENCE,
"exons": [{"number": 1, "start": 1, "end": len(SEQUENCE)}],
}
]
}
path = Path(tempfile.mkdtemp()) / "reference.json"
path.write_text(json.dumps(reference))
return ferro_hgvs.Normalizer(reference_json=str(path))
NEEDS_REFERENCE = [
"TEMPLATE:n.3_7delinsGGCTA",
"TEMPLATE:n.3_5del",
"TEMPLATE:n.3_5inv",
"TEMPLATE:n.3dup",
]
@pytest.mark.parametrize("descriptor", NEEDS_REFERENCE)
def test_the_module_level_conversion_still_declines(descriptor):
with pytest.raises(ferro_hgvs.ProjectionError) as excinfo:
ferro_hgvs.hgvs_to_spdi(ferro_hgvs.parse(descriptor))
assert "reference" in str(excinfo.value).lower()
@pytest.mark.parametrize("descriptor", NEEDS_REFERENCE)
def test_reference_aware_conversion_resolves_them(normalizer, descriptor):
spdi = normalizer.to_spdi(ferro_hgvs.parse(descriptor))
assert spdi.sequence == "TEMPLATE"
def test_reference_aware_conversion_resolves_the_expected_bases(normalizer):
p = ferro_hgvs.parse
assert str(normalizer.to_spdi(p("TEMPLATE:n.3_7delinsGGCTA"))) == "TEMPLATE:2:ATTAC:GGCTA"
assert str(normalizer.to_spdi(p("TEMPLATE:n.3_5del"))) == "TEMPLATE:2:ATT:"
assert str(normalizer.to_spdi(p("TEMPLATE:n.3_5inv"))) == "TEMPLATE:2:ATT:AAT"
def test_canonical_spdi_is_the_same_for_two_encodings(normalizer):
p = ferro_hgvs.parse
spanning = normalizer.canonical_spdi(p("TEMPLATE:n.3_7delinsGGCTA"))
decomposed = normalizer.canonical_spdi(p("TEMPLATE:n.[3A>G;4T>G;5T>C;6A>T;7C>A]"))
assert str(spanning) == str(decomposed)
assert str(spanning) == "TEMPLATE:2:ATTAC:GGCTA"
def test_canonical_spdi_ignores_member_order(normalizer):
p = ferro_hgvs.parse
assert str(normalizer.canonical_spdi(p("TEMPLATE:n.[3A>G;7C>A]"))) == str(
normalizer.canonical_spdi(p("TEMPLATE:n.[7C>A;3A>G]"))
)
def test_different_edits_get_different_keys(normalizer):
p = ferro_hgvs.parse
keys = {
str(normalizer.canonical_spdi(p(d)))
for d in ["TEMPLATE:n.3A>G", "TEMPLATE:n.3A>C", "TEMPLATE:n.4T>G", "TEMPLATE:n.3_5del"]
}
assert len(keys) == 4
def test_apply_to_reference_returns_both_windows(normalizer):
applied = normalizer.apply_to_reference(ferro_hgvs.parse("TEMPLATE:n.3_7delinsGGCTA"))
assert applied.accession == "TEMPLATE"
assert applied.start == 2 assert applied.reference == "ATTAC"
assert applied.resulting == "GGCTA"
assert "AppliedVariant" in repr(applied)
def test_apply_to_reference_agrees_with_the_sequence_itself(normalizer):
applied = normalizer.apply_to_reference(ferro_hgvs.parse("TEMPLATE:n.3_5del"))
start, end = applied.start, applied.start + len(applied.reference)
assert applied.reference == SEQUENCE[start:end]
assert applied.resulting == ""
@pytest.mark.parametrize(
"descriptor",
[
"TEMPLATE:n.[3_5del;4T>G]",
"TEMPLATE:n.[3A>G(;)7C>A]",
],
)
def test_shapes_without_one_resulting_sequence_are_refused(normalizer, descriptor):
variant = ferro_hgvs.parse(descriptor)
with pytest.raises(ferro_hgvs.ProjectionError):
normalizer.canonical_spdi(variant)
with pytest.raises(ferro_hgvs.ProjectionError):
normalizer.apply_to_reference(variant)
def test_an_unknown_accession_is_refused(normalizer):
with pytest.raises(ferro_hgvs.ProjectionError):
normalizer.canonical_spdi(ferro_hgvs.parse("ABSENT:n.3A>G"))
def test_applied_variant_is_exported():
assert "AppliedVariant" in ferro_hgvs.__all__
assert "SpdiVariant" in ferro_hgvs.__all__