Async toolkit to normalize gene identifiers and annotate gene sets with data from the Alliance of Genome Resources (AGR) or user-ingested datasets.
Project description
geneharmony
An async Python toolkit that normalizes gene identifiers and annotates gene sets using the Alliance of Genome Resources (AGR) REST API and bulk-download files, with functionality to append local annotations.
It resolves gene symbols and identifiers to canonical genes using an in-memory index built from AGR's bulk gene file, fetches per-gene API data concurrently, and downloads and parses AGR bulk datasets.
Highlights
- Gene normalization: Resolve symbols, primary/secondary IDs, synonyms, systematic names, and external cross-references (NCBI, Ensembl, UniProtKB, RefSeq, …) to the appropriate records in the AGR's
GENE-TSV-COMBINEDfile. - Nine model organisms: Human, mouse, rat, zebrafish, fly, worm, yeast, african clawed frog, and western clawed frog.
- Concurrent and resilient: Pooled, rate-limited HTTP with automatic retry/backoff for transient failures.
- Transparent caching: Bulk files, per-gene API results, and ingested annotations are cached as Parquet to expedite repeat runs.
- Bring your own data: Ingest external annotation tables keyed on whatever gene identifier you have; they normalize to canonical AGR genes and join cleanly.
Install
Requires Python 3.12+. Install from PyPI with pip or uv — all dependencies (httpx, pydantic v2, pandas 3.x, pyarrow) are resolved automatically:
pip install geneharmony
# or
uv add geneharmony
Development
Contributors use pixi (conda-forge) for a reproducible environment from the lockfile. End users do not need pixi.
# 1. Install the environment from the lockfile
pixi install
# 2. Run Python inside the environment
pixi run python <script>
# 3. Or open the interactive driver notebook
pixi run jupyter lab src/notebook.ipynb
Notebook outputs are stripped from version control via a git clean filter. The filter config is repo-local, so enable it once per clone:
git config filter.nbstrip.clean "pixi run jupyter nbconvert --clear-output --to notebook --stdin --stdout --log-level=ERROR"
git config filter.nbstrip.smudge cat
Usage
The Annotator is the single entry point. It is async, so call its methods with await (inside a notebook cell, an async def, or asyncio.run(...)).
Quick start
from geneharmony import Annotator, AGRDataset
ann = Annotator()
# Resolve gene symbols to canonical AGR records
genes = await ann.normalize(["TP53", "BRCA1"], taxon="human")
# Annotate genes with phenotypic information
annotated_genes = await ann.annotate(["Atp7b", "Ttn"], AGRDataset.PHENOTYPES, taxon="mouse")
Resolving genes (normalize)
normalize accepts an identifier or a list of identifiers and returns one row per match. Unmatched queries are retained with a null match_kind so misses stay visible.
df = await ann.normalize(
["TP53", "ENSG00000141510", "not_a_gene"],
taxon="human", # any alias: "human", "9606", "Homo sapiens", "NCBITaxon:9606"
limit=1, # max matches per query; use None for all
case_insensitive=False, # case can be meaningful (human TP53 vs mouse Trp53)
)
resolved = df[df.match_kind.notna()] # drop the misses
Matches are ranked by identifier precedence:
PRIMARY_ID > SECONDARY_ID > OFFICIAL_SYMBOL > SYNONYM > CROSS_REFERENCE
Annotating genes (annotate)
annotate builds a normalized base frame, then left joins one or more sources onto the canonical GeneId:
from geneharmony import AGRDataset
orth = await ann.annotate(
["TP53", "BRCA1"],
AGRDataset.ORTHOLOGY,
taxon="human",
)
For chaining annotate calls, the recommended pattern is an iterative filter-then-requery traversal — one AGR dataset per call — so result cardinality stays under your control:
# 1. Find orthologs of human genes
orth = await ann.annotate(["TP53", "BRCA1"], AGRDataset.ORTHOLOGY, taxon="human")
# 2. Keep the mouse orthologs
mouse = orth.loc[orth.Gene2SpeciesTaxonID == "NCBITaxon:10090", "Gene2ID"].unique()
# 3. Fetch their phenotypes
pheno = await ann.annotate(list(mouse), AGRDataset.PHENOTYPES, taxon="mouse")
Available AGR datasets
| Dataset | Backend | Key columns contributed |
|---|---|---|
AGRDataset.ORTHOLOGY |
Bulk TSV | Gene2ID, Gene2Symbol, Gene2SpeciesTaxonID, … |
AGRDataset.PHENOTYPES |
Per-gene API | phenotypeStatement, references |
AGRDataset.ALLELES |
Per-gene API | allele_id, symbol, alterationType, variantType, … |
Orthologs convenience helper
For the common ortholog case there is a shortcut that returns a tidy subset:
orthologs = await ann.get_orthologs(
["TP53", "BRCA1"],
taxon="human",
target_taxon="mouse", # optional: filter to one target species
)
# -> columns: query, match_kind, Gene2ID, Gene2Symbol, Gene2SpeciesTaxonID
Downloading bulk datasets (download)
Bulk datasets are downloaded and converted to Parquet on first use (and cached thereafter). You can pre-fetch one explicitly:
path = await ann.download(AGRDataset.ORTHOLOGY)
# Force a refresh across AGR releases:
path = await ann.download(AGRDataset.ORTHOLOGY, refresh=True)
Ingesting your own annotations (ingest_annotation)
Bring an external table (CSV, TSV, or Parquet file, or a DataFrame), normalize its gene identifiers to canonical AGR genes, and store it for joining by name:
summary, unmapped = await ann.ingest_annotation(
"my_expression_table.csv",
name="expression",
gene_id_column="symbol", # or a list of columns, tried left-to-right per row
taxon="human",
)
# Join it alongside an AGR dataset; its columns are prefixed `expression.`
df = await ann.annotate(["TP53", "BRCA1"], AGRDataset.ORTHOLOGY, "expression", taxon="human")
summary reports rows in / stored / dropped; unmapped holds the rows whose identifiers could not be resolved (with their original columns) so nothing is silently lost.
Supported species
| Common name | Species | Taxon ID |
|---|---|---|
| human | Homo sapiens | NCBITaxon:9606 |
| mouse | Mus musculus | NCBITaxon:10090 |
| rat | Rattus norvegicus | NCBITaxon:10116 |
| zebrafish | Danio rerio | NCBITaxon:7955 |
| fly / fruit fly | Drosophila melanogaster | NCBITaxon:7227 |
| worm / roundworm | Caenorhabditis elegans | NCBITaxon:6239 |
| yeast / budding yeast | Saccharomyces cerevisiae S288C | NCBITaxon:559292 |
| african clawed frog | Xenopus laevis | NCBITaxon:8355 |
| western clawed frog | Xenopus tropicalis | NCBITaxon:8364 |
Any of the aliases above — common name, full species name, bare number, or NCBITaxon: ID — can be passed as taxon.
Caching
Results are cached so repeat work is fast and largely offline. The cache defaults to $XDG_CACHE_HOME/geneharmony (falling back to ~/.cache/geneharmony); pass a cache_dir to Annotator(...) to share or relocate it.
bulk/<dataset>.parquet # downloaded + converted bulk datasets (incl. the gene index source)
api/<dataset>/<gene_id>.parquet # per-gene API results
external/<name>.parquet # ingested annotations
The gene index is built from bulk/gene.parquet, which becomes stale across AGR releases. Refresh it with await ann.download(AGRDataset.GENE, refresh=True) (or by deleting the file).
Acknowledgements & Citation
This project is a client for data and services provided by the Alliance of Genome Resources (AGR). It is not affiliated with or endorsed by the Alliance. All gene, ortholog, phenotype, and allele data are sourced from AGR and its member model-organism databases, and remain subject to the Alliance's terms of use.
If you use data obtained through this wrapper, please cite the Alliance of Genome Resources:
Updates to the Alliance of Genome Resources central infrastructure. 2024. Alliance of Genome Resources Consortium. Genetics. 2024 May 7;227(1):iyae049. doi: 10.1093/genetics/iyae049. PMID: 38552170.
Please also consult the Alliance citation and data-usage guidelines and acknowledge the underlying model-organism databases (e.g. SGD, WormBase, FlyBase, ZFIN, MGI, RGD, Xenbase) as appropriate.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 geneharmony-0.3.0.tar.gz.
File metadata
- Download URL: geneharmony-0.3.0.tar.gz
- Upload date:
- Size: 88.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
765b720859c2c026ad5c060b8b6ac396adf4d9c55933d4b357c0f6c30a4b5c00
|
|
| MD5 |
e97f4036be5b3fa8fd58187c60edd04e
|
|
| BLAKE2b-256 |
092767f095a03cb7c3953ebc75bfb820a1a314190fd600c350a34ad67eb76346
|
Provenance
The following attestation bundles were made for geneharmony-0.3.0.tar.gz:
Publisher:
publish.yml on limenode/geneharmony
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
geneharmony-0.3.0.tar.gz -
Subject digest:
765b720859c2c026ad5c060b8b6ac396adf4d9c55933d4b357c0f6c30a4b5c00 - Sigstore transparency entry: 2024934169
- Sigstore integration time:
-
Permalink:
limenode/geneharmony@d66234c9b8c55a41508e9c53e3f7d683ad02413c -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/limenode
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d66234c9b8c55a41508e9c53e3f7d683ad02413c -
Trigger Event:
release
-
Statement type:
File details
Details for the file geneharmony-0.3.0-py3-none-any.whl.
File metadata
- Download URL: geneharmony-0.3.0-py3-none-any.whl
- Upload date:
- Size: 21.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a7d3373a3c1bb03876ff6f47c9c323a3b17f18c0ecccd2f07aaf32c3e0f2a6a3
|
|
| MD5 |
8b739ea0c079c430223fef6cf2ee6c66
|
|
| BLAKE2b-256 |
87610100192af300e6e36dbe30813c7f09b941710798b4d313cc53348e8d7926
|
Provenance
The following attestation bundles were made for geneharmony-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on limenode/geneharmony
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
geneharmony-0.3.0-py3-none-any.whl -
Subject digest:
a7d3373a3c1bb03876ff6f47c9c323a3b17f18c0ecccd2f07aaf32c3e0f2a6a3 - Sigstore transparency entry: 2024934276
- Sigstore integration time:
-
Permalink:
limenode/geneharmony@d66234c9b8c55a41508e9c53e3f7d683ad02413c -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/limenode
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d66234c9b8c55a41508e9c53e3f7d683ad02413c -
Trigger Event:
release
-
Statement type: