High-performance HGVS variant mapping and validation engine.
Registered on PyPI as hgvs-weaver.
Registered on Crates.io as hgvs-weaver.
weaver is a high-performance engine for parsing, validating, and mapping HGVS variants. It provides a robust Python interface backed by a core implementation in Rust, designed for high-throughput variant interpretation pipelines.
A key feature of weaver is its use of Rust's type system to ensure coordinate system integrity. Internally, the library employs "tagged integers" to represent positions in different coordinate spaces:
GenomicPos: 0-based inclusive genomic coordinates.TranscriptPos: 0-based inclusive transcript coordinates (distance from the transcription start site).ProteinPos: 0-based inclusive amino acid positions.
The library also uses explicit types for HGVS-style 1-based coordinates:
HgvsGenomicPos: 1-based genomic coordinates.HgvsTranscriptPos: 1-based cDNA/non-coding coordinates, which correctly skip the non-existent position 0 (e.g., jumps from-1to1).HgvsProteinPos: 1-based amino acid positions.
By enforcing these types at compile time in Rust, weaver prevents common off-by-one errors and accidental mixing of coordinate systems during complex mapping operations (e.g., from g. to c. to p.).
weaver supports a wide range of HGVS variant types and operations:
- Parsing: robust parsing of
g.,m.,c.,n.,r., andp.variants. - Mapping:
- Genomic to Coding (
g.toc.). - Coding to Genomic (
c.tog.). - Coding to Protein (
c.top.) with full translation.
- Genomic to Coding (
- Normalization: Automatic 3' shifting of variants in repetitive regions.
- Complex Edits: Support for deletions (
del), insertions (ins), duplications (dup), inversions (inv), and repeats ([n]).
import weaver
# Parsing and Formatting
v = weaver.parse("NM_000051.3:c.123A>G")
print(v.format()) # "NM_000051.3:c.123A>G"
# Mapping c. to p.
# (Requires a DataProvider, see below)
v_p = mapper.c_to_p(v)
print(v_p.format()) # "NP_000042.3:p.(Lys41Arg)"
# Normalization (3' shifting)
v_raw = weaver.parse("NM_000051.3:c.4_5del")
v_norm = mapper.normalize_variant(v_raw)
print(v_norm.format()) # e.g., "NM_000051.3:c.5_6del"To perform mapping operations, weaver requires an object that implements the DataProvider protocol. This object is responsible for providing transcript models and reference sequences.
When implementing a DataProvider, you must provide coordinates in the following formats:
-
Transcript Models:
cds_start_index: The 0-based inclusive index of the first base of the start codon (A of ATG) relative to the transcript start.cds_end_index: The 0-based inclusive index of the last base of the stop codon relative to the transcript start.- Exons:
transcript_start: 0-based inclusive start index in the transcript.transcript_end: 0-based exclusive end index in the transcript.reference_start: 0-based inclusive start index on the genomic reference.reference_end: 0-based inclusive end index on the genomic reference.
-
Sequence Retrieval:
get_seq(ac, start, end, kind): Should return the sequence for accessionac.startandendare 0-based half-open (interbase) coordinates.
class DataProvider(Protocol):
def get_transcript(self, transcript_ac: str, reference_ac: str | None) -> TranscriptData:
"""Return a dictionary matching the TranscriptData structure."""
...
def get_seq(self, ac: str, start: int, end: int, kind: str | IdentifierType) -> str:
"""Fetch sequence for an accession. kind is an IdentifierType."""
...
def get_symbol_accessions(self, symbol: str, source_kind: str, target_kind: str) -> list[tuple[str, str]] | list[tuple[IdentifierType, str]]:
"""Map gene symbols to accessions (e.g., 'ATM' -> [('transcript_accession', 'NM_000051.3')])."""
...
def get_identifier_type(self, identifier: str) -> str | IdentifierType:
"""Identify what type of identifier a string is (e.g., 'genomic_accession', 'gene_symbol')."""
...This repository includes a dataset of 100,000 variants sampled from ClinVar (August 2025 release) for validation purposes, located in data/clinvar_variants_100k.tsv.
ClinVar License & Terms: ClinVar data is public domain and available for use under the terms of the National Library of Medicine (NLM). Use of ClinVar data must adhere to their citation and data use policies.
pip install hgvs-weaverimport weaver
# Parse a variant
var = weaver.parse("NM_000051.3:c.123A>G")
print(var.ac) # NM_000051.3
print(var.format()) # NM_000051.3:c.123A>Gweaver has been extensively validated against ClinVar data to ensure accuracy and parity with the standard Python HGVS implementation.
To rerun the validation, you need the RefSeq annotation and genomic sequence files:
-
Download Required Files:
# Download RefSeq GFF curl -O https://ftp.ncbi.nlm.nih.gov/refseq/H_sapiens/annotation/GRCh38_latest/refseq_identifiers/GRCh38_latest_genomic.gff.gz # Download RefSeq FASTA and decompress curl -O https://ftp.ncbi.nlm.nih.gov/refseq/H_sapiens/annotation/GRCh38_latest/refseq_identifiers/GRCh38_latest_genomic.fna.gz gunzip GRCh38_latest_genomic.fna.gz
-
Install Validation Dependencies:
pip install pysam tqdm bioutils parsley pip install hgvs --no-deps # Avoids psycopg2 build requirement -
Run Validation: You can run the validation using the installed entry point (if you installed with
[validation]extra):weaver-validate data/clinvar_variants_100k.tsv \ --output-file results.tsv \ --gff GRCh38_latest_genomic.gff.gz \ --fasta GRCh38_latest_genomic.fnaAlternatively, if you use
uv, you can run the script directly from the source tree without manually installing dependencies (it will use the PEP 723 metadata to auto-install them):uv run weaver/cli/validate.py data/clinvar_variants_100k.tsv ...
Summary of results comparing weaver and ref-hgvs against ClinVar ground truth:
| Implementation | Identity Match | Analogous Match | Total Success |
|---|---|---|---|
| weaver | 93.85% | 4.92% | 98.77% |
| ref-hgvs | 93.34% | 4.88% | 98.22% |
RefSeq Data Mismatches: 0 (0.0%)
As shown in the visualization above, weaver now consistently outperforms existing implementations in protein projection accuracy and biological equivalence.
- Variant Equivalence: Check if two variants are biologically equivalent using advanced cross-coordinate mapping and normalization. See Algorithm.
If you encounter a linking error like dyld: symbol not found in flat namespace '_PyBool_Type' when running stub_gen, it is because the extension-module feature (enabled by default for Python bindings) conflicts with standalone binary execution on some platforms (like macOS).
To fix this, run stub_gen with default features disabled:
cargo run --bin stub_gen --no-default-features