54 AI: Directing to resources
A companion clinic on building on machinery you did not write, rehearsing the move the codon-bias project and the finale both ask of you.
You now have the two halves separately: reading a library’s documentation as a set of contracts, and catching the assistant when it invents one that does not exist. This clinic puts both halves to work on an actual small task, live, the way you will need to on this week’s project and, eventually, on the finale. The task: given a DNA coding sequence, report whether its reverse complement, read as a coding sequence, translates cleanly to a protein with no internal stop codon.
Deciding what the task needs before asking for anything
Before typing a single prompt, name the capabilities the task actually requires, the way you would decompose a task into functions. This one needs a reverse complement of a DNA sequence, a translation of a DNA sequence into a protein, and a check for whether a stop codon, shown by BioPython as *, appears anywhere before the final position of that protein. The first two are exactly the Seq methods you met two notes ago. The third is not a library operation at all, it is a small piece of logic over the result, which matters: you are about to direct the assistant to combine library calls, and knowing in advance which parts are the library’s job and which part is yours is what keeps you from asking it to reinvent .translate() badly, or from quietly accepting logic it wrote for the one part you should have written yourself.
Checking the contracts before prompting
Two methods, two contracts to confirm from the actual documentation, not from memory or from what the assistant assumes. Seq.reverse_complement() takes no required arguments and returns a new Seq. Seq.translate() takes an optional to_stop argument; read its entry and you will find that when to_stop=True, translation stops at the first in-frame stop codon and the * is simply omitted from the result, rather than translation continuing past it the way the default behaves. That single optional argument changes which of two different questions the code answers, and choosing between them is a decision you make before prompting, not one you leave for the assistant to make silently.
Directing the assistant
With the contracts in hand, the prompt can be exact: “Using Bio.Seq.Seq, write a function translates_cleanly(dna) that takes a DNA coding sequence, returns its reverse complement, translates it with to_stop=False so any internal stop codon stays visible in the result, and returns True if the resulting protein contains no * before its final character.” Notice how much of that sentence is contract, not code: which method, which argument, which behavior you are relying on. A vague version of the same request, “check if the reverse complement translates okay,” leaves the assistant to guess to_stop’s value the same way it once guessed a tie-breaking rule, and you would have no way to know which guess it made without reading the code closely enough that you might as well have specified it yourself.
Verifying the result, twice
The assistant’s answer gets checked in the two different ways this course has been building toward. First, against the documentation: did it call .reverse_complement() and .translate() with real arguments that mean what you asked, or does anything in the call look invented, the way .gc_content() did? Second, against a test, because a documented call can still be assembled into wrong logic:
from Bio.Seq import Seq
def translates_cleanly(dna):
"True if the reverse complement's translation has no internal stop codon."
protein = Seq(dna).reverse_complement().translate(to_stop=False)
return '*' not in protein[:-1]
assert translates_cleanly('ATGGCCTGA') in (True, False) # runs at all
print(translates_cleanly('ATGGCCTGA'))Work out by hand what 'ATGGCCTGA'’s reverse complement is, and what that translates to, and confirm the function’s answer against your own. That hand-worked case is the sanity check standing in for the test you cannot write against a library you trust as machinery: you are not testing that .translate() implements the genetic code correctly, you are checking that the pieces were assembled the way you specified.
Why this is the rehearsal it claims to be
Nothing about this clinic was larger than a single function. What it rehearsed was the shape of every later task that leans on a library: decide what capabilities you need before prompting, confirm their contracts in the real documentation, direct the assistant with the contract instead of a mood, and verify twice, once against the documentation and once against a hand-worked case. The codon-bias project this week, and the finale later, are this same shape, just with more pieces.
Exercise 54-1
Direct the assistant to write a function longest_orf_protein(dna) that finds the longest open reading frame in a DNA sequence starting at any ATG and translates it, using Bio.Seq.Seq for the translation step only; the search for ATG and the comparison of lengths is logic you specify, not a library call. Before prompting, decide and write down which part is the library’s job and which is yours, the way this clinic did.
For your logbook this week, name one library call from this week’s project that you verified against real documentation before trusting it, and one you are not fully sure you checked closely enough.