pythonforbio.
[WASM idle]
Library Overview01/06

Biopython

Starting sandbox…
Beginnerlesson

Biopython

In one line: the standard library for reading biological file formats and manipulating the objects inside them.

Version at time of writing: 1.87 (Mar 2026) · import Bio · install as biopython

The mental model

Biopython is a parser collection plus a small object model. It is not an analysis engine. It reads a format, hands you objects, lets you manipulate them, and writes them back out.

The object model is three layers deep and you will use it constantly:

SeqIO.parse(file, fmt)  ──▶  iterator of SeqRecord
                                  ├─ .seq         → Seq        (the letters)
                                  ├─ .id, .description
                                  ├─ .annotations  → dict
                                  └─ .features     → [SeqFeature]
                                                        └─ .location  (0-based, half-open)

Almost every module follows the same parse (many records, lazy) / read (exactly one record, errors otherwise) / write naming. Learn it once for SeqIO and AlignIO, Bio.Phylo, Bio.PDB and Bio.Blast all feel familiar.

Read this before any old tutorial

Biopython has been aggressively removing things. Two removals invalidate most pre-2026 material:

  • Bio.Application was removed in 1.86. Every command-line wrapper — NcbiblastnCommandline, MuscleCommandline, ClustalwCommandline, all of Bio.Blast.Applications and Bio.Align.Applications — is gone. Use subprocess directly.
  • Bio.Alphabet was removed in 1.78. Seq("ATG", IUPAC.unambiguous_dna) is a TypeError now. Sequences are just letters; molecule type lives in record.annotations["molecule_type"] when a format needs it.

Also gone: Bio.SubsMat (→ Bio.Align.substitution_matrices), Bio.SeqUtils.GC (→ gc_fraction), Seq.ungap(), Seq.tomutable(). Bio.pairwise2 is deprecated in favour of PairwiseAligner. Full table in Biopython Deprecations.

What it does and does not do

Does well: parsing (FASTA, FASTQ, GenBank, EMBL, SwissProt, PDB/mmCIF, Clustal, Stockholm, Newick, BLAST XML, and dozens more), sequence manipulation, pairwise alignment, NCBI Entrez access, phylogenetic tree handling, structure geometry, motif/PWM work, restriction analysis.

Does not do: BAM/CRAM (use pysam), tabix-indexed queries (pysam), fast VCF (pysam/cyvcf2), read mapping, assembly, variant calling, statistical testing. It also is not the fastest FASTQ parser available — for tens of millions of reads, a specialised tool or pyfastx will beat it.

Core notes

Sequences Seq · SeqRecord · SeqIO · SeqFeature and Location · Bio.SeqUtils

Alignment PairwiseAligner · Substitution Matrices · AlignIO

Databases and external tools Bio.Entrez · Bio.Blast

Structures, trees, motifs Bio.PDB · Bio.Phylo · Bio.motifs · Bio.Restriction

Housekeeping Biopython Deprecations

Applied

Applied - FASTA and FASTQ Workflows · Applied - Sequence Composition Analysis · Applied - Multiple Sequence Alignment Analysis · Applied - Genomic File Formats · Applied - Quality Control Plots

Install and check

pip install "biopython>=1.86,<2"
python -c "import Bio; print(Bio.__version__)"

The import name is Bio, the package name is biopython. This trips people up in requirements files.

The 20% that gets 80% of the work done

from Bio import SeqIO
from Bio.Seq import Seq
from Bio.SeqUtils import gc_fraction

# stream a large file — never load it all
for rec in SeqIO.parse("reads.fastq", "fastq"):
    q = rec.letter_annotations["phred_quality"]
    if min(q) < 20:
        continue
    print(rec.id, len(rec), gc_fraction(rec.seq))

# one record
rec = SeqIO.read("NM_000546.gb", "genbank")
rec.seq.reverse_complement()
rec.seq.translate(to_stop=True)

# random access without loading everything
idx = SeqIO.index("genome.fasta", "fasta")
chr17 = idx["chr17"]

# format conversion
SeqIO.convert("in.gb", "genbank", "out.fasta", "fasta")

Gotchas that bite newcomers

  • SeqIO.parse returns a one-pass iterator. Iterating twice yields nothing the second time. Wrap in list() only if the file is small.
  • SeqIO.read raises if the file has zero or more than one record. That is a feature — it catches assumptions.
  • Seq is immutable. Use MutableSeq to edit in place.
  • translate() warns on partial codons and does not stop at a stop codon unless you pass to_stop=True.
  • Feature locations are 0-based half-open even when the source format was 1-based. Do not adjust them yourself. See Coordinate Systems.
  • Entrez requires Bio.Entrez.email to be set, and NCBI rate-limits you. See Bio.Entrez.

See also

biocommons hgvs · Ecosystem Map · Coordinate Systems · Learning Path

scratch

No output yet — run the code to populate this drawer.

start of pathMatplotlib