Search DNA sequences for restriction enzyme recognition sites with Bio.Restriction, for a single enzyme, a curated panel, or a whole commercial set, on linear or circular DNA. The result is a list of cut positions per enzyme, plus the ability to filter enzymes by how many times they cut.
pip install biopython
A DNA sequence in FASTA or GenBank format. Use GenBank when the molecule is a plasmid so the agent can read its circular topology and features.
Tell your AI agent what you want to do: - "Find all EcoRI sites in my plasmid sequence" - "Search for EcoRI, BamHI, and HindIII sites in this DNA" - "Which commercial enzymes cut my insert exactly once?" - "Does NotI cut this sequence at all?"
"Find all EcoRI cut sites in plasmid.fasta"
"Where does BamHI cut in my sequence, treating it as circular?"
"Search for EcoRI, BamHI, and HindIII sites in my plasmid"
"Find all commercially available enzymes that cut my sequence exactly once"
"Which enzymes cut my sequence twice?"
"Find all enzymes that don't cut my insert sequence"
RestrictionBatch, CommOnly, or AllEnzymes.linear=False for plasmids).from Bio import SeqIO
from Bio.Restriction import EcoRI
record = SeqIO.read('plasmid.fasta', 'fasta')
sites = EcoRI.search(record.seq, linear=False) # circular plasmid
print(f'EcoRI cuts at: {sites}')
from Bio.Restriction import RestrictionBatch, Analysis, EcoRI, BamHI, HindIII
batch = RestrictionBatch([EcoRI, BamHI, HindIII])
analysis = Analysis(batch, seq)
for enzyme, sites in analysis.with_sites().items(): # only enzymes that cut
print(f'{enzyme}: {sites}')
from Bio.Restriction import Analysis, CommOnly
analysis = Analysis(CommOnly, seq)
once = analysis.with_N_sites(1) # cut exactly once (linearization)
twice = analysis.with_N_sites(2) # cut exactly twice (excision)
none = analysis.without_site() # do not cut at all (safe in a digest)
Note: the with_N_sites(n) / with_sites() / without_site() names are the current BioPython API. Older guides used once_cutters() / twice_cutters() / only_dont_cut(), which raise AttributeError in current versions.
A position is 1-based and equals the first base of the downstream fragment, i.e. the base immediately 3' of the cut on the top strand. It is NOT the start of the recognition site:
seq: ...G A A T T C... EcoRI site GAATTC starts at position p
cut: ^ top-strand cut is between G and A
search(): returns p+1 (the A after the cut), not p
Read the cut geometry directly with elucidate():
EcoRI.elucidate() # 'G^AATT_C' -> ^ top-strand cut, _ bottom-strand cut, 5' overhang AATT
sites = EcoRI.search(seq, linear=True) # linear molecule (PCR product, genomic fragment)
sites = EcoRI.search(seq, linear=False) # plasmid; finds sites spanning the origin
EcoRI.site # 'GAATTC' recognition site
EcoRI.is_blunt() # False
EcoRI.is_5overhang() # True
EcoRI.ovhg # -4 (negative = 5' overhang, positive = 3', zero = blunt)
EcoRI.ovhgseq # 'AATT'
EcoRI.is_ambiguous() # False (True for N-spacer sites like BstXI; NOT for IUPAC sites like HincII)
| Collection | Description |
|---|---|
| AllEnzymes | All known enzymes (1088 in current REBASE build), including non-commercial |
| CommOnly | Commercially available only (623); the practical default |
| Custom RestrictionBatch | A panel of enzymes chosen for the experiment |
linear=False for plasmid sequences, or sites near the origin are missed.CommOnly so the answer is an enzyme that can actually be purchased.ovhg means a 5' overhang; confirm any end with elucidate().Bio.Restriction (capital R). Empty results usually mean the sequence is protein or the wrong topology.