import json
from pathlib import Path
import ferro_hgvs
def _variants(n: int) -> list[str]:
assert n >= 3, "need n >= 3 for two distinct, in-bounds error indices"
vs = [f"NM_000088.3:c.{i}A>G" for i in range(1, n + 1)]
vs[1] = "definitely not a variant"
vs[n - 1] = "also::not:valid"
return vs
def _key(result) -> tuple:
return (
result.total(),
result.success_count(),
result.error_count(),
[str(v) for v in result.successes()],
list(result.errors()),
)
def test_parse_parallel_matches_serial() -> None:
bp = ferro_hgvs.BatchProcessor()
variants = _variants(5000)
serial = _key(bp.parse(variants, workers=1))
assert serial[1] > 0, "expected some successful parses"
assert serial[2] == 2, "expected exactly the two injected errors"
for workers in (0, 2, 4, 8):
assert _key(bp.parse(variants, workers=workers)) == serial, (
f"parse(workers={workers}) differs from serial"
)
def test_parse_and_normalize_parallel_matches_serial() -> None:
bp = ferro_hgvs.BatchProcessor()
variants = _variants(5000)
serial = _key(bp.parse_and_normalize(variants, workers=1))
assert serial[1] > 0, "expected some successful parses"
assert serial[2] == 2, "expected exactly the two injected errors"
for workers in (0, 2, 4, 8):
assert _key(bp.parse_and_normalize(variants, workers=workers)) == serial, (
f"parse_and_normalize(workers={workers}) differs from serial"
)
def test_parallel_is_deterministic() -> None:
bp = ferro_hgvs.BatchProcessor()
variants = _variants(4000)
a = _key(bp.parse_and_normalize(variants, workers=8))
b = _key(bp.parse_and_normalize(variants, workers=8))
assert a == b
def test_default_workers_is_parallel_and_correct() -> None:
bp = ferro_hgvs.BatchProcessor()
variants = _variants(2000)
assert _key(bp.parse(variants)) == _key(bp.parse(variants, workers=1))
def _genome_bp(tmp_path: Path) -> "ferro_hgvs.BatchProcessor":
seq = ["A"] * 5000
for i in range(1000, 4000, 7):
seq[i] = "G"
ref = {
"transcripts": [],
"proteins": {},
"genomic_sequences": {"NC_000001.11": "".join(seq)},
}
path = tmp_path / "genome_ref.json"
path.write_text(json.dumps(ref))
return ferro_hgvs.BatchProcessor(reference_json=str(path))
def _genome_variants(n: int) -> list[str]:
assert n >= 3, "need n >= 3 for two distinct, in-bounds error indices"
vs = [f"NC_000001.11:g.{100 + i}del" for i in range(n)]
vs[1] = "definitely not a variant"
vs[n - 1] = "also::not:valid"
return vs
def test_parse_and_rederive_parallel_matches_serial(tmp_path: Path) -> None:
bp = _genome_bp(tmp_path)
variants = _genome_variants(2000)
serial = _key(bp.parse_and_rederive(variants, workers=1))
assert serial[1] > 0, "expected successful rederivations, not an all-error corpus"
assert serial[2] == 2, "expected exactly the two injected parse errors"
for workers in (0, 2, 4, 8):
assert _key(bp.parse_and_rederive(variants, workers=workers)) == serial, (
f"parse_and_rederive(workers={workers}) differs from serial"
)
def _insertion_repeat_bp(tmp_path: Path) -> "ferro_hgvs.BatchProcessor":
ref = {
"transcripts": [],
"proteins": {},
"genomic_sequences": {"NC_TEST.1": "GCTAGCATCGATC"},
}
path = tmp_path / "insertion_repeat_ref.json"
path.write_text(json.dumps(ref))
return ferro_hgvs.BatchProcessor(reference_json=str(path))
def test_parse_and_rederive_recommended_form_runs_parallel(tmp_path: Path) -> None:
bp = _insertion_repeat_bp(tmp_path)
variants = ["NC_TEST.1:g.7_8insAAA"]
for workers in (0, 1, 2, 4, 8):
plain = bp.parse_and_rederive(variants, recommended_form=False, workers=workers)
recommended = bp.parse_and_rederive(variants, recommended_form=True, workers=workers)
assert [str(v) for v in plain.successes()] == ["NC_TEST.1:g.7_8insAAA"], (
f"recommended_form=False (workers={workers}) must keep the literal insertion"
)
assert [str(v) for v in recommended.successes()] == ["NC_TEST.1:g.7A[4]"], (
f"recommended_form=True (workers={workers}) must collapse to repeat notation"
)
def test_parse_and_rederive_is_deterministic(tmp_path: Path) -> None:
bp = _genome_bp(tmp_path)
variants = _genome_variants(1000)
a = _key(bp.parse_and_rederive(variants, workers=8))
b = _key(bp.parse_and_rederive(variants, workers=8))
assert a == b
def test_parse_and_rederive_rejects_zero_grid() -> None:
import pytest
bp = ferro_hgvs.BatchProcessor()
with pytest.raises(ValueError):
bp.parse_and_rederive(["NM_000088.3:c.1A>G"], max_grid_cells=0)