syntheogenesis / tests /test_resolve.py
Tengo Gzirishvili
Fix AlphaFold viewer showing nothing (stale model version + silent 404)
20cdca4
Raw
History Blame Contribute Delete
6.35 kB
"""Paste-anything target resolution (dee/core/resolve.py).
NO NETWORK β€” Ensembl/NCBI fetchers are monkeypatched. Locks the input
classifier (sequence vs symbol vs accession) and the resolve dispatch,
including the privacy-preserving rule that raw sequences make no calls.
"""
import pytest
from dee.core import resolve as R
from dee.core import exon as E
from dee.core.exon import Exon, GeneStructure
# ─────────────────────────── classifier ───────────────────────────
@pytest.mark.parametrize("text,kind", [
("", "empty"),
("ACGT" * 10, "sequence"), # 40 nt one-liner
(">hdr\nACGTACGTACGTACGTACGTACGT", "sequence"), # FASTA
("TP53", "symbol"),
("BRCA1", "symbol"),
("ENST00000269305", "ensembl_tx"),
("ENSMUST00000000001", "ensembl_tx"),
("ENSG00000141510", "ensembl_gene"),
("NM_000546", "refseq"),
("NM_000546.6", "refseq"),
("XM_011535573", "refseq"),
("!!!", "unknown"),
])
def test_classify(text, kind):
assert R.classify(text)[0] == kind
def test_classify_sequence_strips_to_clean_dna():
kind, val = R.classify("acgt ACGT\nnnNN gtca gtca gtca")
assert kind == "sequence"
assert val == "ACGTACGTNNNNGTCAGTCAGTCA"
# ─────────────────────────── raw sequence (offline) ───────────────────────────
def test_resolve_raw_sequence_makes_no_network_call(monkeypatch):
# Any network helper firing would be a privacy bug for raw input.
def _boom(*a, **k):
raise AssertionError("network call on raw-sequence path!")
monkeypatch.setattr(E, "_http_get_text", _boom)
monkeypatch.setattr(E, "_http_get_json", _boom)
monkeypatch.setattr(E, "fetch_gene_structure", _boom)
out = R.resolve_target("ACGT" * 20)
assert out["ok"] and out["kind"] == "sequence"
assert out["sequence"] == "ACGT" * 20
assert "pasted sequence" in out["label"]
def test_resolve_short_sequence_errors():
out = R.resolve_target("ACGTACGT") # < 23 nt β†’ symbol attempt β†’ fails
assert out["ok"] is False
# ─────────────────────────── gene symbol ───────────────────────────
def _fake_gene():
return GeneStructure(
organism="human", gene_symbol="TP53", transcript_id="ENST00000269305",
strand=1, cds_sequence="ATG" + "GCT" * 50 + "TAA",
exons=[Exon(1, 1, 99, 0, 156)], last_junction_cds_pos=0,
)
def test_resolve_symbol_requires_organism():
out = R.resolve_target("TP53", organism="")
assert out["ok"] is False and "Human or" in out["error"]
def test_resolve_symbol_with_organism(monkeypatch):
monkeypatch.setattr(E, "fetch_gene_structure", lambda org, sym: _fake_gene())
out = R.resolve_target("TP53", organism="human")
assert out["ok"] and out["kind"] == "gene"
assert out["gene_symbol"] == "TP53"
assert out["sequence"].startswith("ATG")
assert "ENST00000269305" in out["label"]
def test_resolve_symbol_not_found(monkeypatch):
monkeypatch.setattr(E, "fetch_gene_structure", lambda org, sym: None)
out = R.resolve_target("ZZZ9", organism="mouse")
assert out["ok"] is False and "Couldn't find" in out["error"]
# ─────────────────────────── accessions ───────────────────────────
def test_resolve_ensembl_transcript(monkeypatch):
monkeypatch.setattr(E, "_http_get_text",
lambda url, **k: ">ENST\nATGAAACCCGGGTTTACGTACGTACGT")
out = R.resolve_target("ENST00000269305")
assert out["ok"] and out["kind"] == "ensembl"
assert out["sequence"] == "ATGAAACCCGGGTTTACGTACGTACGT"
def test_resolve_ensembl_gene_resolves_canonical(monkeypatch):
monkeypatch.setattr(E, "_http_get_json", lambda url, **k: {
"Transcript": [
{"id": "ENST_other", "is_canonical": 0},
{"id": "ENST_canon", "is_canonical": 1},
]})
captured = {}
def _seq(url, **k):
captured["url"] = url
return ">x\nATGCGTACGTACGTACGTACGTACG"
monkeypatch.setattr(E, "_http_get_text", _seq)
out = R.resolve_target("ENSG00000141510")
assert out["ok"] and out["kind"] == "ensembl"
assert "ENST_canon" in captured["url"] # used the canonical transcript
def test_resolve_refseq(monkeypatch):
monkeypatch.setattr(E, "_http_get_text",
lambda url, **k: ">NM_000546\nATGGAGGAGCCGCAGTCAGAT")
out = R.resolve_target("NM_000546")
assert out["ok"] and out["kind"] == "refseq"
assert out["sequence"] == "ATGGAGGAGCCGCAGTCAGAT"
def test_resolve_ensembl_fetch_failure(monkeypatch):
monkeypatch.setattr(E, "_http_get_text", lambda url, **k: None)
out = R.resolve_target("ENST00000269305")
assert out["ok"] is False and "Ensembl" in out["error"]
# ─────────────────────────── UniProt / structure (M5) ───────────────────────────
def test_resolve_uniprot_ok(monkeypatch):
captured = {}
def _json(url, **k):
captured["url"] = url
return {"results": [{"primaryAccession": "P04637"}]}
monkeypatch.setattr(E, "_http_get_json", _json)
out = R.resolve_uniprot("human", "TP53")
assert out["ok"] and out["uniprot"] == "P04637"
assert out["alphafold_url"] == "https://alphafold.ebi.ac.uk/files/AF-P04637-F1-model_v6.pdb"
assert out["alphafold_page"] == "https://alphafold.ebi.ac.uk/entry/P04637"
assert "organism_id%3A9606" in captured["url"] and "reviewed%3Atrue" in captured["url"]
def test_resolve_uniprot_no_hit(monkeypatch):
monkeypatch.setattr(E, "_http_get_json", lambda url, **k: {"results": []})
out = R.resolve_uniprot("human", "ZZZ9")
assert out["ok"] is False
def test_resolve_uniprot_bad_organism():
assert R.resolve_uniprot("ecoli", "lacZ")["ok"] is False