File size: 8,216 Bytes
1bf37a2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
"""Tests for sequence-visible expression risk (audit #24).

Two things are actually being defended here: that no yield is ever predicted,
and that the rare-codon threshold is derived from the tables rather than
chosen β€” the second is what makes the first honest rather than merely cautious.
"""
import pytest

from dee.core import expression as E

ADAPTED = "ATG" + "AAACTGGCGCGTGAAGATCTGAAAGCGGTTCTGGAAAAC" * 3 + "TAA"
RARE_HEAVY = "ATG" + "AAACTGGCGAGAAGGATAGATCTGAAAGCGGTTCTGGAAAAC" * 3 + "TAA"


# ── the honesty contract ─────────────────────────────────────────────────
def test_no_expression_level_is_ever_predicted():
    r = E.assess(ADAPTED, "e_coli")
    assert r["ok"]
    assert "does NOT predict an expression level" in r["no_yield"]
    for key in ("yield", "expression_level", "mg_per_l", "predicted_yield",
                "expression_score"):
        assert key not in r


def test_the_result_names_what_it_does_not_cover():
    """An assessment that looks complete is worse than one that lists its own
    blind spots β€” the user assumes the unchecked thing was checked."""
    n = E.assess(ADAPTED, "e_coli")["not_covered"]
    assert "Shine-Dalgarno" in n
    assert "#38" in n and "#39" in n
    assert "assess_solubility" in n


# ── the threshold is derived, and the derivation is checkable ────────────
def test_the_rare_cutoff_selects_the_codons_rosetta_strains_supply():
    """w < 0.15 against the E. coli table selects AGA, AGG, ATA, CTA β€” exactly
    the set argU/ileY/leuW exist to supply. That is the evidence the cutoff is
    measuring something real rather than being a round number."""
    selected = set(E.assess(ADAPTED, "e_coli")["rare_codons_in_this_host"])
    assert {"AGA", "AGG", "ATA", "CTA"} <= selected


def test_the_same_cutoff_finds_nothing_rare_in_human_and_says_so():
    """Mammalian codon usage is much flatter. Manufacturing a warning to look
    thorough would be worse than the empty result."""
    r = E.assess(ADAPTED, "human")
    assert r["rare_codons_in_this_host"] == []
    assert r["rare_codon_count"] == 0
    assert "nothing" in r["method"]


def test_the_method_line_lists_the_selected_codons():
    m = E.assess(ADAPTED, "e_coli")["method"]
    assert "Sharp & Li" in m
    assert str(E.RARE_BELOW) in m
    assert "AGA" in m


# ── rare codons and the runs that matter ─────────────────────────────────
def test_an_adapted_sequence_is_clean():
    r = E.assess(ADAPTED, "e_coli")
    assert r["rare_codon_count"] == 0
    assert r["flags"] == []
    assert r["codon_adaptation_index"] > 0.9


def test_rare_codons_lower_the_adaptation_index():
    assert (E.assess(RARE_HEAVY, "e_coli")["codon_adaptation_index"]
            < E.assess(ADAPTED, "e_coli")["codon_adaptation_index"])


def test_consecutive_rare_codons_are_reported_as_a_run():
    """The finding that changes what someone does. A scattered rare codon is
    absorbed; three in a row depletes the local charged-tRNA pool."""
    r = E.assess(RARE_HEAVY, "e_coli")
    assert r["rare_codon_runs"]
    run = r["rare_codon_runs"][0]
    assert run["length"] >= E.RUN_LENGTH
    assert run["codons"] == ["AGA", "AGG", "ATA"]
    flag = [f for f in r["flags"] if "consecutive rare" in f["factor"]][0]
    assert "recoding just this run" in flag["why"]


def test_scattered_rare_codons_do_not_form_a_run():
    dna = "ATG" + ("AGA" + "CTGGCGAAAGATCTGGAA") * 6 + "TAA"
    r = E.assess(dna, "e_coli")
    assert r["rare_codon_count"] >= 6
    assert r["rare_codon_runs"] == []


def test_the_five_prime_ramp_is_reported_separately():
    """A rare codon at codon 5 costs more than the same codon at codon 400."""
    r = E.assess(RARE_HEAVY, "e_coli")
    assert r["rare_in_ramp"]
    assert all(x["codon_number"] <= E.RAMP_CODONS for x in r["rare_in_ramp"])


def test_cai_excludes_single_codon_families():
    """Met and Trp have no synonym to choose between. Including them only
    drags every score toward 1 and makes a bad sequence look adapted."""
    only_mw = "ATG" + "ATGTGG" * 20 + "TAA"
    r = E.assess(only_mw, "e_coli")
    assert r["codon_adaptation_index"] is None or r["codon_adaptation_index"] > 0


def test_cai_does_not_underflow_on_a_long_cds():
    """The direct product of hundreds of fractions underflows to 0.0 and
    silently reports a perfectly adapted gene as unadapted."""
    long_cds = "ATG" + "AAACTGGCGCGTGAAGATCTGAAAGCGGTTCTGGAAAAC" * 60 + "TAA"
    cai = E.assess(long_cds, "e_coli")["codon_adaptation_index"]
    assert cai is not None and cai > 0.5


# ── reading frame ────────────────────────────────────────────────────────
def test_an_internal_stop_is_flagged_as_a_truncated_product():
    dna = "ATG" + "AAACTGGCG" * 4 + "TAA" + "AAACTGGCG" * 6 + "TAA"
    r = E.assess(dna, "e_coli")
    assert r["internal_stops"]
    flag = [f for f in r["flags"] if "internal stop" in f["factor"]][0]
    assert "truncated" in flag["why"]


def test_a_missing_terminal_stop_is_flagged():
    r = E.assess(ADAPTED[:-3], "e_coli")
    assert r["has_terminal_stop"] is False
    assert any("no terminal stop" in f["factor"] for f in r["flags"])


def test_an_out_of_frame_length_is_flagged_not_silently_truncated():
    r = E.assess(ADAPTED + "AT", "e_coli")
    assert r["in_frame"] is False
    assert any("whole number of codons" in f["factor"] for f in r["flags"])


# ── hosts ────────────────────────────────────────────────────────────────
def test_an_unknown_host_declines_instead_of_using_another_table():
    """Scoring a plant construct against the E. coli table would produce
    confident nonsense. The refusal must read as missing data, not as the
    organism being unsupported."""
    r = E.assess(ADAPTED, "plant")
    assert r["ok"] is False and r["kind"] == "no_codon_table"
    assert "missing data file, not an unsupported organism" in r["next"]


def test_a_missing_host_is_refused_because_expression_is_host_specific():
    assert E.assess(ADAPTED, "")["ok"] is False


def test_every_known_host_alias_works():
    for host in ("e_coli", "ecoli", "yeast", "s_cerevisiae", "human", "h_sapiens"):
        assert E.assess(ADAPTED, host)["ok"], host


def test_the_same_sequence_scores_differently_per_host():
    """The point of asking for a host. E. coli-optimised DNA is not
    human-optimised."""
    a = E.assess(ADAPTED, "e_coli")["codon_adaptation_index"]
    b = E.assess(ADAPTED, "human")["codon_adaptation_index"]
    assert a != b


def test_too_short_is_refused():
    assert E.assess("ATGAAACTG", "e_coli")["kind"] == "too_short"


# ── the agent tool ───────────────────────────────────────────────────────
def test_the_tool_runs_and_needs_a_host():
    from dee.core import agent_tools as t
    fn = t._TOOLS["assess_expression"]["fn"]
    assert fn({"dna": ADAPTED, "host": "e_coli"})["ok"]
    assert fn({"host": "e_coli"})["ok"] is False


def test_the_tool_explains_that_protein_input_cannot_answer_this():
    from dee.core import agent_tools as t
    err = t._TOOLS["assess_expression"]["fn"]({"host": "e_coli"})["error"]
    assert "reverse-translate" in err


def test_the_spec_forbids_substituting_another_hosts_table():
    from dee.core import agent_tools as t
    desc = next(s for s in t.TOOL_SPECS
                if s["function"]["name"] == "assess_expression")["function"]["description"]
    assert "never substitute another host's table" in desc
    assert "no_yield" in desc
    # No enum on host β€” a hardcoded organism list is the hardest gate to see.
    props = next(s for s in t.TOOL_SPECS
                 if s["function"]["name"] == "assess_expression")["function"]["parameters"]["properties"]
    assert "enum" not in props["host"]