Flexible and fast antibody sequence annotation in Rust with python bindings
Project description
immunum
High-performance antibody and TCR sequence numbering in Rust, Python, and WebAssembly.
Overview
immunum is a library for numbering antibody and T-cell receptor (TCR) variable domain sequences. It uses Needleman-Wunsch semi-global alignment against position-specific scoring matrices built from consensus sequences, with BLOSUM62-based substitution scores.
Available as:
- Rust crate — core library and CLI
- Python package — with a Polars plugin for vectorized batch processing
- npm package — for Node.js and browsers
Supported chains
| Antibody | TCR |
|---|---|
| IGH (heavy) | TRA (alpha) |
| IGK (kappa) | TRB (beta) |
| IGL (lambda) | TRD (delta) |
| TRG (gamma) |
Chain codes: H (IGH), K (IGK), L (IGL), A (TRA), B (TRB), D (TRD), G (TRG).
Chain type is automatically detected by aligning against all loaded chains and selecting the best match.
Numbering schemes
- IMGT — all 7 chain types
- Kabat — antibody chains (IGH, IGK, IGL)
Table of Contents
Python
Installation
pip install immunum
Numbering
from immunum import Annotator
annotator = Annotator(chains=["H", "K", "L"], scheme="imgt")
sequence = "QVQLVQSGAEVKRPGSSVTVSCKASGGSFSTYALSWVRQAPGRGLEWMGGVIPLLTITNYAPRFQGRITITADRSTSTAYLELNSLRPEDTAVYYCAREGTTGKPIGAFAHWGQGTLVTVSS"
result = annotator.number(sequence)
print(result.chain) # H
print(result.confidence) # 0.78
print(result.numbering) # {"1": "Q", "2": "V", "3": "Q", ...}
Segmentation
segment splits the sequence into FR/CDR regions:
from immunum import Annotator
annotator = Annotator(chains=["H", "K", "L"], scheme="imgt")
sequence = "QVQLVQSGAEVKRPGSSVTVSCKASGGSFSTYALSWVRQAPGRGLEWMGGVIPLLTITNYAPRFQGRITITADRSTSTAYLELNSLRPEDTAVYYCAREGTTGKPIGAFAHWGQGTLVTVSS"
result = annotator.segment(sequence)
assert result.fr1 == 'QVQLVQSGAEVKRPGSSVTVSCKAS'
assert result.cdr1 == 'GGSFSTYA'
assert result.fr2 == 'LSWVRQAPGRGLEWMGG'
assert result.cdr2 == 'VIPLLTIT'
assert result.fr3 == 'NYAPRFQGRITITADRSTSTAYLELNSLRPEDTAVYYC'
assert result.cdr3 == 'AREGTTGKPIGAFAH'
assert result.fr4 == 'WGQGTLVTVSS'
Polars plugin
For batch processing, immunum.polars registers elementwise Polars expressions:
import polars as pl
import immunum.polars as imp
df = pl.DataFrame({"sequence": [
"QVQLVQSGAEVKRPGSSVTVSCKASGGSFSTYALSWVRQAPGRGLEWMGGVIPLLTITNYAPRFQGRITITADRSTSTAYLELNSLRPEDTAVYYCAREGTTGKPIGAFAHWGQGTLVTVSS",
"DIQMTQSPSSLSASVGDRVTITCRASQDVNTAVAWYQQKPGKAPKLLIYSASFLYSGVPSRFSGSRSGTDFTLTISSLQPEDFATYYCQQHYTTPPTFGQGTKVEIK",
]})
# Add a struct column with chain, scheme, confidence, numbering
result = df.with_columns(
imp.number(pl.col("sequence"), chains=["H", "K", "L"], scheme="imgt").alias("numbered")
)
# Add a struct column with FR/CDR segments
result = df.with_columns(
imp.segment(pl.col("sequence"), chains=["H", "K", "L"], scheme="imgt").alias("segmented")
)
The number expression returns a struct with fields chain, scheme, confidence, and numbering (a struct of position→residue). The segment expression returns a struct with fields fr1, cdr1, fr2, cdr2, fr3, cdr3, fr4, prefix, postfix.
JavaScript / npm
Installation
npm install immunum
Usage
const { Annotator } = require("immunum");
const annotator = new Annotator(["H", "K", "L"], "imgt");
const sequence =
"QVQLVQSGAEVKRPGSSVTVSCKASGGSFSTYALSWVRQAPGRGLEWMGGVIPLLTITNYAPRFQGRITITADRSTSTAYLELNSLRPEDTAVYYCAREGTTGKPIGAFAHWGQGTLVTVSS";
const result = annotator.number(sequence);
console.log(result.chain); // "H"
console.log(result.confidence); // 0.97
console.log(result.numbering); // { "1": "Q", "2": "V", ... }
const segments = annotator.segment(sequence);
console.log(segments.cdr3); // "AREGTTGKPIGAFAH"
annotator.free(); // or use `using annotator = new Annotator(...)` with explicit resource management
Rust
Installation
Add to Cargo.toml:
[dependencies]
immunum = "0.9"
Usage
use immunum::{Annotator, Chain, Scheme};
let annotator = Annotator::new(
&[Chain::IGH, Chain::IGK, Chain::IGL],
Scheme::IMGT,
None, // uses default min_confidence of 0.5
).unwrap();
let sequence = "QVQLVQSGAEVKRPGSSVTVSCKASGGSFSTYALSWVRQAPGRGLEWMGGVIPLLTITNYAPRFQGRITITADRSTSTAYLELNSLRPEDTAVYYCAREGTTGKPIGAFAHWGQGTLVTVSS";
let result = annotator.number(sequence).unwrap();
println!("Chain: {}", result.chain); // IGH
println!("Confidence: {:.2}", result.confidence);
for (aa, pos) in sequence.chars().zip(result.positions.iter()) {
println!("{} -> {}", aa, pos);
}
let segments = annotator.segment(sequence).unwrap();
println!("CDR3: {}", segments.cdr3);
CLI
immunum number [OPTIONS] [INPUT] [OUTPUT]
Options
| Flag | Description | Default |
|---|---|---|
-s, --scheme |
Numbering scheme: imgt (i), kabat (k) |
imgt |
-c, --chain |
Chain filter: h,k,l,a,b,g,d or groups: ig, tcr, all. Accepts any form (h, heavy, igh), case-insensitive. |
ig |
-f, --format |
Output format: tsv, json, jsonl |
tsv |
Input
Accepts a raw sequence, a FASTA file, or stdin (auto-detected):
immunum number EVQLVESGGGLVKPGGSLKLSCAASGFTFSSYAMS
immunum number sequences.fasta
cat sequences.fasta | immunum number
immunum number - < sequences.fasta
Output
Writes to stdout by default, or to a file if a second positional argument is given:
immunum number sequences.fasta results.tsv
immunum number -f json sequences.fasta results.json
Examples
# Kabat scheme, JSON output
immunum number -s kabat -f json EVQLVESGGGLVKPGGSLKLSCAASGFTFSSYAMS
# All chains (antibody + TCR), JSONL output
immunum number -c all -f jsonl sequences.fasta
# TCR sequences only, save to file
immunum number -c tcr tcr_sequences.fasta output.tsv
# Extract sequences from a TSV column and pipe in (see fixtures/ig.tsv)
tail -n +2 fixtures/ig.tsv | cut -f2 | immunum number
awk -F'\t' 'NR==1{for(i=1;i<=NF;i++) if($i=="sequence") c=i} NR>1{print $c}' fixtures/ig.tsv | immunum number
# Filter TSV output to CDR3 positions (111-128 in IMGT)
immunum number sequences.fasta | awk -F'\t' '$4 >= 111 && $4 <= 128'
# Filter to heavy chain results only
immunum number -c all sequences.fasta | awk -F'\t' 'NR==1 || $2=="H"'
# Extract CDR3 sequences with jq
immunum number -f json sequences.fasta | jq '[.[] | {id: .sequence_id, numbering}]'
Development
To orchestrate a project between cargo and python, we use task.
You can install it with:
uv tool install go-task-bin
And then run task or task --list-all to get the full list of available tasks.
By default, dev profile will be used in all but benchmark-* tasks, but you can change it
via providing PROFILE=release to your task.
Also, by default, task caches results, but you can ignore it by running task my-task -f.
Building local environment
# build a dev environment
task build-local
# build a dev environment with --release flag
task build-local PROFILE=release
Testing
task test-rust # test only rust code
task test-python # test only python code
task test # test all code
Linting
task format # formats python and rust code
task lint # runs linting for python and rust
Benchmarking
There are multiple benchmarks in the repository. For full list, see task | grep benchmark:
$ task | grep benchmark
* benchmark-accuracy: Accuracy benchmark across all fixtures (1k sequences, 7 rounds each)
* benchmark-cli: Benchmark correctness of the CLI tool
* benchmark-comparison: Speed + correctness benchmark: immunum vs antpack vs anarci (1k IGH sequences)
* benchmark-scaling: Scaling benchmark: sizes 100..10M (10x steps), 1 round, H/imgt. Pass CLI_ARGS to filter tools, e.g. -- --tools immunum
* benchmark-speed: Speed benchmark across dataset sizes (100 to 1M sequences, 7 rounds, H/imgt)
* benchmark-speed-polars: Speed benchmark for immunum polars across all chain/scheme fixtures
Project structure
src/
├── main.rs # CLI binary (immunum number ...)
├── lib.rs # Public API
├── annotator.rs # Sequence annotation and chain detection
├── alignment.rs # Needleman-Wunsch semi-global alignment
├── io.rs # Input parsing (FASTA, raw) and output formatting (TSV, JSON, JSONL)
├── numbering.rs # Numbering module entry point
├── numbering/
│ ├── imgt.rs # IMGT numbering rules
│ └── kabat.rs # Kabat numbering rules
├── scoring.rs # PSSM and scoring matrices
├── types.rs # Core domain types (Chain, Scheme, Position)
├── validation.rs # Validation utilities
├── error.rs # Error types
└── bin/
├── benchmark.rs # Validation metrics report
├── debug_validation.rs # Alignment mismatch visualization
└── speed_benchmark.rs # Performance benchmarks
resources/
└── consensus/ # Consensus sequence CSVs (compiled into scoring matrices)
fixtures/
├── validation/ # ANARCI-numbered reference datasets
├── ig.fasta # Example antibody sequences
└── ig.tsv # Example TSV input
scripts/ # Python tooling for generating consensus data
immunum/
├── _internal.pyi # python stub file for pyo3
├── polars.py # polars extension module
└── python.py # python module
Design decisions
- Semi-global alignment forces full query consumption, preventing long CDR3 regions from being treated as trailing gaps.
- Anchor positions at highly conserved FR residues receive 3× gap penalties to stabilize alignment.
- FR regions use alignment-based numbering; CDR regions use scheme-specific insertion rules.
- Scoring matrices are generated at compile time from consensus data via
build.rs.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file immunum-1.0.0.tar.gz.
File metadata
- Download URL: immunum-1.0.0.tar.gz
- Upload date:
- Size: 86.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc4f6dc41338ec0f3b78704f5006ccc7a913fddb5e5b6139f41f304531ac9f2e
|
|
| MD5 |
433490ba85f8fa65b82839c57532a447
|
|
| BLAKE2b-256 |
5af326f25925bb840572f83e37cfc993812dcce43383a8b3c78049e899fb0c7e
|
File details
Details for the file immunum-1.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: immunum-1.0.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 4.8 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d9f03b62039d4dc2c8ba62b54612f5e39d921bd907f4d5bfd2cc08ea0184a9e
|
|
| MD5 |
cdc5d25d57bf3828eba7899209b8c661
|
|
| BLAKE2b-256 |
a565dd15d7aab3477390bed35a6e3d3dca3eed27f32f988d808118ed308e7eb8
|
File details
Details for the file immunum-1.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: immunum-1.0.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 4.6 MB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b2952ddf9c3f106e8cb6594d9effb0b9a27a1491b98505f67d5977e6e086f28
|
|
| MD5 |
18d2dc9f0483c95c9d58f093b9dc8c3b
|
|
| BLAKE2b-256 |
f11444cc2137a5b1fe0f89c27a1d4127c5884670d88c845d7045fa9252f7126a
|
File details
Details for the file immunum-1.0.0-cp39-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: immunum-1.0.0-cp39-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.4 MB
- Tags: CPython 3.9+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de2d9d56a364bf2694a10bb0d406502ceb7ff118bde7bf6d1c319908e682f4ba
|
|
| MD5 |
408e9cccb5ac20b21c48629a5c85d939
|
|
| BLAKE2b-256 |
9abf23676067736c45109a8c77a70d35757001b9d9f14cd7553ade1322fd1376
|