pythonforbio.
[WASM idle]
HGVS Nomenclature04/11

SeqRepo

Starting sandbox…
Beginnerlesson

SeqRepo

In one line: a local, immutable, versioned store of biological sequences with fast random access by accession — what UTA and Data Providers is for alignments, SeqRepo is for the sequences themselves.

Why it exists

Validation and normalization need the actual bases. To know whether NM_000546.6:c.215C>G is valid, you must know that base 215 really is a C. To 3'-shift a deletion, you must be able to read the surrounding sequence.

Fetching that from NCBI per variant is slow, rate-limited, and — crucially — not reproducible, because remote records change. SeqRepo solves all three by keeping a versioned local snapshot.

Installing

pip install seqrepo
seqrepo --root-directory /usr/local/share/seqrepo pull
seqrepo --root-directory /usr/local/share/seqrepo list-local-instances

export HGVS_SEQREPO_DIR=/usr/local/share/seqrepo/2024-02-20

Roughly 15 GB for a full human snapshot. Sizeable, but you download it once and it never changes — immutability is the design.

Without HGVS_SEQREPO_DIR, hgvs falls back to fetching sequences remotely (via SeqRepo REST or NCBI), which works and is slow.

Direct use

from biocommons.seqrepo import SeqRepo

sr = SeqRepo("/usr/local/share/seqrepo/2024-02-20")

sr["NM_000546.6"]                        # the full sequence
sr["NM_000546.6"][214:215]               # 0-based slice → the base at c. position 215
sr["NC_000017.11"][7676153:7676154]      # a genomic base
len(sr["NC_000017.11"])

sr.translate_alias("NM_000546.6")        # every known alias for this sequence
sr.translate_identifier("refseq:NM_000546.6")

Slicing is 0-based half-open (Python convention) while HGVS positions are 1-based. Hence [214:215] for HGVS position 215. This is the Coordinate Systems conversion, and it is exactly the kind of thing you should let the library do rather than doing by hand.

The namespace system

SeqRepo keys sequences by digest, not by accession, and treats accessions as aliases:

sr.translate_alias("NM_000546.6")
# [{'namespace': 'refseq',    'alias': 'NM_000546.6'},
#  {'namespace': 'ensembl',   'alias': 'ENST00000269305.9'},
#  {'namespace': 'ga4gh',     'alias': 'SQ.xxxxx...'},
#  {'namespace': 'MD5',       'alias': '...'},
#  ...]

Two consequences worth understanding:

  1. Deduplication. RefSeq and Ensembl often distribute byte-identical sequences under different accessions. SeqRepo stores one copy.
  2. Content-addressed identity. The ga4gh:SQ. digest identifies the sequence by its content, so two accessions with the same digest are provably the same sequence. This is the foundation of GA4GH VRS — the successor scheme to string-based variant identity.

Immutability

Once a snapshot is created it never changes. New releases are new directories:

/usr/local/share/seqrepo/
    2021-01-29/
    2023-05-15/
    2024-02-20/

This is the property that makes reproducibility possible. A pipeline that records HGVS_SEQREPO_DIR=.../2024-02-20 can be re-run in five years and produce identical output. One that fetches from NCBI cannot.

Use with hgvs

Set the environment variable and hgvs uses it automatically:

export HGVS_SEQREPO_DIR=/usr/local/share/seqrepo/2024-02-20

Or explicitly:

from hgvs.dataproviders.seqfetcher import SeqFetcher
sf = SeqFetcher()
sf.fetch_seq("NM_000546.6", 214, 215)          # 0-based, half-open

The fetcher resolution order is: HGVS_SEQREPO_DIR → SeqRepo REST service → NCBI E-utilities. The first is fast and reproducible; the last is neither.

Verifying reference bases

The single most useful thing SeqRepo enables:

def check_ref(sr, var):
    """Does the variant's stated ref base actually match the sequence?"""
    ref = getattr(var.posedit.edit, "ref", None)
    if not ref:
        return None                                   # nothing to check
    start = var.posedit.pos.start.base - 1            # 1-based → 0-based
    actual = sr[var.ac][start:start + len(ref)]
    return actual == ref

A mismatch means one of: the wrong accession version, the wrong assembly (GRCh37 vs GRCh38), a strand error, or a genuinely bad record. All four are common, and all four are silent without this check. hgvs Validator does this for you.

Adding your own sequences

seqrepo --root-directory /path/to/seqrepo init -i my_instance
seqrepo --root-directory /path/to/seqrepo load -i my_instance -n mynamespace custom.fasta

Useful for custom references, patient-specific assemblies, or transcripts absent from RefSeq.

SeqRepo vs the alternatives

SeqRepo pysam.FastaFile Bio.SeqIO.index
Random access yes yes yes
Cross-namespace aliases yes no no
Content-addressed yes no no
Immutable/versioned yes no no
Transcripts + genome together yes one file at a time one file at a time
Ecosystem biocommons/VRS samtools Biopython

For variant work, SeqRepo's advantages are decisive: one lookup interface for transcripts and chromosomes, alias resolution across RefSeq/Ensembl, and immutability. For a plain reference FASTA in a read-alignment pipeline, pysam.FastaFile is simpler.

Disk and setup cost

The 15 GB and the setup are the main objections to SeqRepo, and they are real. The honest cost–benefit:

  • Exploring a few variants: skip it. Use remote fetching via hgvs easy.
  • Any pipeline, any clinical work, anything you will publish: install it. The reproducibility argument alone justifies the disk, and the speed difference on batch work is large.

Common mistakes

  • Not setting HGVS_SEQREPO_DIR, silently falling back to slow remote fetching.
  • 1-based/0-based confusion when slicing directly.
  • Not recording the snapshot date in your outputs.
  • Assuming an accession is present. Older or suppressed versions may not be in a given snapshot.
  • Mixing snapshots between development and production.
  • Fetching sequences remotely in a loop.
  • Pointing HGVS_SEQREPO_DIR at the root rather than at a specific dated instance directory.

See also

UTA and Data Providers · hgvs Validator · hgvs Normalizer · hgvs easy · Coordinate Systems · Applied - Reproducible Environment

lesson example

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