BioThings.io is a platform that provides a network of high-performance biomedical APIs and tools for building FAIR (Findable, Accessible, Interoperable, and Reusable) data services. The platform includes several key components:
- Core BioThings APIs:
- MyGene.info - Gene Annotation Service
- MyVariant.info - Variant Annotation Service
- MyChem.info - Chemical and Drug Annotation Service
- MyDisease.info - Disease Annotation Service
- Taxonomy API - For querying taxonomic information
This typed client library is built on top of the BioThings ecosystem, providing type-safe access to these services through Python.
A strongly-typed Python wrapper around the BioThings Client library, providing type safety and better IDE support through Python's type hints and Pydantic models.
- Type Safety & Validation: Leverages Pydantic models for runtime data validation and type checking.
- Enhanced IDE Support: Full autocompletion and static analysis in modern IDEs
- Synchronous & Asynchronous: Support for both sync and async operations
- Helper Methods: Additional utility methods for common operations
- Compatibility: Maintains full compatibility with the original BioThings client
git clone https://github.com/longevity-genie/biothings-typed-client.git
cd biothings-typed-clientpip install biothings-typed-clientIf you want to contribute to this repository:
-
Clone the repository (if you haven't already):
git clone https://github.com/longevity-genie/biothings-typed-client.git cd biothings-typed-client -
Install UV:
curl -LsSf https://astral.sh/uv/install.sh | sh -
Create and activate a virtual environment:
uv venv source .venv/bin/activate # On Unix/macOS # or .venv\Scripts\activate # On Windows
-
Install all dependencies, including development tools:
uv sync
This command reads the
pyproject.tomlfile and installs the package in editable mode along with all its dependencies and optional dependencies (like those needed for testing and development).
from biothings_typed_client.variants import VariantClient
# Initialize the client
client = VariantClient()
# Get a single variant
variant = client.getvariant("chr7:g.140453134T>C")
if variant:
print(f"Variant ID: {variant.get_variant_id()}")
print(f"Chromosome: {variant.chrom}")
print(f"Position: {variant.vcf.position}")
print(f"Reference: {variant.vcf.ref}")
print(f"Alternative: {variant.vcf.alt}")
# Get multiple variants
variants = client.getvariants(["chr7:g.140453134T>C", "chr9:g.107620835G>A"])
for variant in variants:
print(f"Found variant: {variant.get_variant_id()}")
# Query variants
results = client.query("dbnsfp.genename:cdk2", size=5)
for hit in results["hits"]:
print(f"Found variant: {hit['_id']}")import asyncio
from biothings_typed_client.variants import VariantClientAsync
async def main():
# Initialize the client
client = VariantClientAsync()
# Get a single variant
variant = await client.getvariant("chr7:g.140453134T>C")
if variant:
print(f"Variant ID: {variant.get_variant_id()}")
print(f"Has clinical significance: {variant.has_clinical_significance()}")
print(f"Has functional predictions: {variant.has_functional_predictions()}")
# Query variants
results = await client.query("dbnsfp.genename:cdk2", size=5)
print("\nQuery results:")
print(results)
# Run the async code
asyncio.run(main())from biothings_typed_client.genes import GeneClient
# Initialize the client
client = GeneClient()
# Get a single gene
gene = client.getgene("1017") # Using Entrez ID
if gene:
print(f"Gene ID: {gene.id}")
print(f"Symbol: {gene.symbol}")
print(f"Name: {gene.name}")
# Get multiple genes
genes = client.getgenes(["1017", "1018"]) # Using Entrez IDs
for gene in genes:
print(f"Found gene: {gene.symbol} ({gene.name})")
# Query genes
results = client.query("symbol:CDK2", size=5)
for hit in results["hits"]:
print(f"Found gene: {hit['symbol']} ({hit['name']})")
# Batch query genes
genes = client.querymany(["CDK2", "BRCA1"], scopes=["symbol"], size=1)
for gene in genes:
print(f"Found gene: {gene['symbol']} ({gene['name']})")import asyncio
from biothings_typed_client.genes import GeneClientAsync
async def main():
# Initialize the client
client = GeneClientAsync()
# Get a single gene
gene = await client.getgene("1017") # Using Entrez ID
if gene:
print(f"Gene ID: {gene.id}")
print(f"Symbol: {gene.symbol}")
print(f"Name: {gene.name}")
# Query genes
results = await client.query("symbol:CDK2", size=5)
print("\nQuery results:")
for hit in results["hits"]:
print(f"Found gene: {hit['symbol']} ({hit['name']})")
# Run the async code
asyncio.run(main())from biothings_typed_client.chem import ChemClient
# Initialize the client
client = ChemClient()
# Get a single chemical
chem = client.getchem("ZRALSGWEFCBTJO-UHFFFAOYSA-N") # Using InChI key
print(f"Chemical ID: {chem.id}")
print(f"Molecular Formula: {chem.pubchem.molecular_formula}")
print(f"SMILES: {chem.pubchem.smiles}")
print(f"Molecular Weight: {chem.pubchem.molecular_weight}")
print(f"XLogP: {chem.pubchem.xlogp}")
print(f"Hydrogen Bond Donors: {chem.pubchem.hydrogen_bond_donor_count}")
print(f"Hydrogen Bond Acceptors: {chem.pubchem.hydrogen_bond_acceptor_count}")
print(f"Rotatable Bonds: {chem.pubchem.rotatable_bond_count}")
print(f"Topological Polar Surface Area: {chem.pubchem.topological_polar_surface_area} Ų")
# Get multiple chemicals
chems = client.getchems(["ZRALSGWEFCBTJO-UHFFFAOYSA-N", "RRUDCFGSUDOHDG-UHFFFAOYSA-N"])
for chem in chems:
print(f"\nFound chemical: {chem.id}")
if chem.has_pubchem():
print(f"Molecular Formula: {chem.pubchem.molecular_formula}")
print(f"Molecular Weight: {chem.pubchem.molecular_weight}")
# Query chemicals with different field filters
print("\n=== Simple Queries ===")
results = client.query("pubchem.molecular_formula:C6H12O6", size=5)
for hit in results["hits"]:
print(f"Found chemical: {hit['_id']}")
print("\n=== Fielded Queries ===")
results = client.query("pubchem.molecular_weight:[100 TO 200]", size=5)
for hit in results["hits"]:
print(f"Found chemical: {hit['_id']}")
print("\n=== Range Queries ===")
results = client.query("pubchem.xlogp:>2", size=5)
for hit in results["hits"]:
print(f"Found chemical: {hit['_id']}")
print("\n=== Boolean Queries ===")
results = client.query("pubchem.hydrogen_bond_donor_count:>2 AND pubchem.hydrogen_bond_acceptor_count:>4", size=5)
for hit in results["hits"]:
print(f"Found chemical: {hit['_id']}")
# Batch query chemicals with field filtering
chems = client.querymany(
["C6H12O6", "C12H22O11"],
scopes=["pubchem.molecular_formula"],
fields=["pubchem.molecular_weight", "pubchem.xlogp", "pubchem.smiles"],
size=1
)
for chem in chems:
print(f"\nFound chemical: {chem['_id']}")
if 'pubchem' in chem:
print(f"Molecular Weight: {chem['pubchem'].get('molecular_weight')}")
print(f"XLogP: {chem['pubchem'].get('xlogp')}")
print(f"SMILES: {chem['pubchem'].get('smiles')}")import asyncio
from biothings_typed_client.chem import ChemClientAsync
async def main():
# Initialize the client
client = ChemClientAsync()
# Get a single chemical
chem = await client.getchem("ZRALSGWEFCBTJO-UHFFFAOYSA-N") # Using InChI key
if chem:
print(f"Chemical ID: {chem.id}")
print(f"Has PubChem info: {chem.has_pubchem()}")
if chem.has_pubchem():
print(f"Molecular Formula: {chem.pubchem.molecular_formula}")
print(f"Molecular Weight: {chem.pubchem.molecular_weight}")
print(f"XLogP: {chem.pubchem.xlogp}")
print(f"Hydrogen Bond Donors: {chem.pubchem.hydrogen_bond_donor_count}")
print(f"Hydrogen Bond Acceptors: {chem.pubchem.hydrogen_bond_acceptor_count}")
print(f"Rotatable Bonds: {chem.pubchem.rotatable_bond_count}")
print(f"Topological Polar Surface Area: {chem.pubchem.topological_polar_surface_area} Ų")
# Query chemicals with different field filters
print("\n=== Simple Queries ===")
results = await client.query("pubchem.molecular_formula:C6H12O6", size=5)
print("\nQuery results:")
for hit in results["hits"]:
print(f"Found chemical: {hit['_id']}")
print("\n=== Fielded Queries ===")
results = await client.query("pubchem.molecular_weight:[100 TO 200]", size=5)
print("\nQuery results:")
for hit in results["hits"]:
print(f"Found chemical: {hit['_id']}")
print("\n=== Range Queries ===")
results = await client.query("pubchem.xlogp:>2", size=5)
print("\nQuery results:")
for hit in results["hits"]:
print(f"Found chemical: {hit['_id']}")
print("\n=== Boolean Queries ===")
results = await client.query("pubchem.hydrogen_bond_donor_count:>2 AND pubchem.hydrogen_bond_acceptor_count:>4", size=5)
print("\nQuery results:")
for hit in results["hits"]:
print(f"Found chemical: {hit['_id']}")
await client.close()
# Run the async code
asyncio.run(main())The chemical client provides access to detailed chemical compound information from MyChem.info, including:
-
Structural Information:
- Molecular formula
- SMILES strings
- InChI and InChIKey
- IUPAC names
-
Physical Properties:
- Molecular weight
- Exact mass
- Monoisotopic weight
- XLogP (octanol-water partition coefficient)
- Topological polar surface area
-
Chemical Properties:
- Hydrogen bond donors/acceptors
- Rotatable bonds
- Chiral centers
- Formal charge
- Molecular complexity
-
Stereochemistry:
- Chiral atom count
- Chiral bond count
- Defined/undefined stereocenters
For more information about available fields and data sources, see the MyChem.info documentation.
from biothings_typed_client.taxons import TaxonClient
# Initialize the client
client = TaxonClient()
# Get a single taxon
taxon = client.gettaxon(9606) # Using taxon ID for Homo sapiens
if taxon:
print(f"Taxon ID: {taxon.id}")
print(f"Scientific Name: {taxon.scientific_name}")
print(f"Common Name: {taxon.common_name}")
# Get multiple taxa
taxa = client.gettaxons([9606, 10090]) # Homo sapiens and Mus musculus
for taxon in taxa:
print(f"Found taxon: {taxon.scientific_name}")
# Query taxa
results = client.query("scientific_name:Homo sapiens", size=5)
for hit in results["hits"]:
print(f"Found taxon: {hit['scientific_name']}")
# Batch query taxa
taxa = client.querymany(["Homo sapiens", "Mus musculus"], scopes=["scientific_name"], size=1)
for taxon in taxa:
print(f"Found taxon: {taxon['scientific_name']}")import asyncio
from biothings_typed_client.taxons import TaxonClientAsync
async def main():
# Initialize the client
client = TaxonClientAsync()
# Get a single taxon
taxon = await client.gettaxon(9606) # Using taxon ID for Homo sapiens
if taxon:
print(f"Taxon ID: {taxon.id}")
print(f"Has lineage: {taxon.has_lineage()}")
print(f"Has common name: {taxon.has_common_name()}")
# Query taxa
results = await client.query("scientific_name:Homo sapiens", size=5)
print("\nQuery results:")
for hit in results["hits"]:
print(f"Found taxon: {hit['scientific_name']}")
# Run the async code
asyncio.run(main())from biothings_typed_client.variants import VariantClient
# Initialize the client
client = VariantClient()
# Get a single variant
variant = client.getvariant("chr7:g.140453134T>C")
if variant:
print(f"Variant ID: {variant.get_variant_id()}")
print(f"Has clinical significance: {variant.has_clinical_significance()}")
print(f"Variant details: {variant.model_dump_json(indent=2)}")
else:
print("Variant not found")
# Query variants using different syntax
print("\n=== Simple Queries ===")
results = client.query("rs58991260")
print(f"Query 'rs58991260' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
print("\n=== Fielded Queries ===")
results = client.query("dbsnp.vartype:snp")
print(f"Query 'dbsnp.vartype:snp' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
print("\n=== Range Queries ===")
results = client.query("dbnsfp.polyphen2.hdiv.score:>0.99")
print(f"Query 'dbnsfp.polyphen2.hdiv.score:>0.99' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
print("\n=== Wildcard Queries ===")
results = client.query("dbnsfp.genename:CDK?")
print(f"Query 'dbnsfp.genename:CDK?' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
print("\n=== Boolean Queries ===")
results = client.query("_exists_:dbsnp AND dbsnp.vartype:snp")
print(f"Query '_exists_:dbsnp AND dbsnp.vartype:snp' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")import asyncio
from biothings_typed_client.variants import VariantClientAsync
async def main():
client = VariantClientAsync()
# Get a single variant
variant = await client.getvariant("chr7:g.140453134T>C")
if variant:
print(f"Variant ID: {variant.get_variant_id()}")
print(f"Has clinical significance: {variant.has_clinical_significance()}")
print(f"Variant details: {variant.model_dump_json(indent=2)}")
else:
print("Variant not found")
# Query variants using different syntax
print("\n=== Simple Queries ===")
results = await client.query("rs58991260")
print(f"Query 'rs58991260' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
print("\n=== Fielded Queries ===")
results = await client.query("dbsnp.vartype:snp")
print(f"Query 'dbsnp.vartype:snp' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
print("\n=== Range Queries ===")
results = await client.query("dbnsfp.polyphen2.hdiv.score:>0.99")
print(f"Query 'dbnsfp.polyphen2.hdiv.score:>0.99' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
print("\n=== Wildcard Queries ===")
results = await client.query("dbnsfp.genename:CDK?")
print(f"Query 'dbnsfp.genename:CDK?' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
print("\n=== Boolean Queries ===")
results = await client.query("_exists_:dbsnp AND dbsnp.vartype:snp")
print(f"Query '_exists_:dbsnp AND dbsnp.vartype:snp' results: {results['total']} hits")
if results['hits']:
print(f"First result: {results['hits'][0].get('_id', 'No ID')}")
print(f"Score: {results['hits'][0].get('_score', 'No score')}")
await client.close()
# Run the async code
asyncio.run(main())The library provides a comprehensive command-line interface that gives you access to all BioThings APIs directly from your terminal. The CLI supports both table and JSON output formats, field filtering, and caching.
After installing the package, you'll have access to two CLI commands:
biothings-typed-client- Main API interfaceclear-cache- Cache management utility
# Show main help
biothings-typed-client --help
# Show help for a specific API
biothings-typed-client gene --help
biothings-typed-client chem --help
biothings-typed-client variant --help
biothings-typed-client geneset --help
biothings-typed-client taxon --help# Get gene by Entrez ID
biothings-typed-client gene get 1017
# Get gene by Ensembl ID
biothings-typed-client gene get ENSG00000123374
# Get specific fields only
biothings-typed-client gene get 1017 --fields "symbol,name,entrezgene"
# Output as JSON
biothings-typed-client gene get 1017 --format json
# Enable caching
biothings-typed-client gene get 1017 --cache# Get multiple genes (comma-separated)
biothings-typed-client gene list "1017,1018,1019"
# With specific fields
biothings-typed-client gene list "1017,1018" --fields "symbol,name" --format json# Get chemical by InChI Key
biothings-typed-client chem get KTUFNOKKBVMGRW-UHFFFAOYSA-N
# Get multiple chemicals
biothings-typed-client chem list "KTUFNOKKBVMGRW-UHFFFAOYSA-N,XEFQLINVKFYRCS-UHFFFAOYSA-N"
# Get specific PubChem fields
biothings-typed-client chem get KTUFNOKKBVMGRW-UHFFFAOYSA-N --fields "pubchem.molecular_formula,pubchem.molecular_weight"# Get variant by ID
biothings-typed-client variant get "chr7:g.140453134T>C"
# Get multiple variants
biothings-typed-client variant list "chr7:g.140453134T>C,chr9:g.107620835G>A"
# Get specific annotation fields
biothings-typed-client variant get "chr7:g.140453134T>C" --fields "clinvar,cadd,dbsnp"
# JSON output for programmatic use
biothings-typed-client variant get "chr7:g.140453134T>C" --format json# Get geneset by ID
biothings-typed-client geneset get WP100
# Get multiple genesets
biothings-typed-client geneset list "WP100,WP101,WP102"
# Get specific fields
biothings-typed-client geneset get WP100 --fields "name,source,count,genes"# Get human taxonomy info
biothings-typed-client taxon get 9606
# Get multiple taxa
biothings-typed-client taxon list "9606,10090,7955"
# Get specific fields
biothings-typed-client taxon get 9606 --fields "scientific_name,common_name,rank"All commands support these options:
--fields,-f: Comma-separated list of fields to return--format: Output format (tableorjson)--cache: Enable response caching--help: Show command help
Beautiful, human-readable tables with colored output:
$ biothings-typed-client gene get 1017
Gene Information: 1017
┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Field ┃ Value ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ ID │ 1017 │
│ Symbol │ CDK2 │
│ Name │ cyclin dependent kinase 2 │
│ Entrez Gene │ 1017 │
│ Taxonomy ID │ 9606 │
│ Summary │ This gene encodes a member of a family of serine/threonine... │
└─────────────┴─────────────────────────────────────────────────────────────────┘Perfect for programmatic use and pipeline integration:
$ biothings-typed-client gene get 1017 --format json --fields "symbol,name,entrezgene"
{
"id": "1017",
"score": null,
"name": "cyclin dependent kinase 2",
"symbol": "CDK2",
"refseq": null,
"taxid": null,
"entrezgene": 1017,
"ensembl": null,
"uniprot": null,
"summary": null,
"genomic_pos": null
}# Clear cache in current directory
clear-cache
# Clear cache in specific directory
clear-cache /path/to/cache/directory
# Show help
clear-cache --helpThe cache cleaner removes files like:
mychem_cachemygene_cachemyvariant_cachemygeneset_cachemytaxon_cache
#!/bin/bash
# Get gene information and extract symbol
SYMBOL=$(biothings-typed-client gene get 1017 --format json | jq -r '.symbol')
echo "Gene symbol: $SYMBOL"
# Process multiple genes
for gene_id in 1017 1018 1019; do
echo "Processing gene $gene_id..."
biothings-typed-client gene get "$gene_id" --fields "symbol,name" --cache
done# Get variant data and pipe to analysis script
biothings-typed-client variant get "chr7:g.140453134T>C" --format json | python analyze_variant.py
# Batch process with caching enabled
biothings-typed-client gene list "$(cat gene_ids.txt | tr '\n' ',')" --cache --format json > gene_data.json- Use caching (
--cache) for repeated queries - Specify fields (
--fields) to reduce response size - Use JSON format for programmatic processing
- Batch requests when possible using the
listcommands
The library currently provides the following typed clients:
VariantClient/VariantClientAsync: For accessing variant dataGeneClient/GeneClientAsync: For accessing gene dataChemClient/ChemClientAsync: For accessing chemical compound dataTaxonClient/TaxonClientAsync: For accessing taxonomic information- More clients coming soon...
The library provides strongly-typed response models for all data types. For example, the VariantResponse model includes:
class VariantResponse(BaseModel):
id: str = Field(description="Variant identifier")
version: int = Field(description="Version number")
chrom: str = Field(description="Chromosome number")
hg19: GenomicLocation = Field(description="HG19 genomic location")
vcf: VCFInfo = Field(description="VCF information")
# Optional annotation fields
cadd: Optional[CADDScore] = None
clinvar: Optional[ClinVarAnnotation] = None
cosmic: Optional[CosmicAnnotation] = None
dbnsfp: Optional[DbNSFPPrediction] = None
dbsnp: Optional[DbSNPAnnotation] = None
# ... and moreThe response models include useful helper methods:
# Get a standardized variant ID
variant.get_variant_id()
# Check for clinical significance
variant.has_clinical_significance()
# Check for functional predictions
variant.has_functional_predictions()uv run pytest -vvvYou can add -s to also get stdout
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
-
BioThings for the biothings API and original client library
-
This project is part of the Longevity Genie organization, which develops open-source AI assistants and libraries for health, genetics, and longevity research.
We are supported by:
HEALES - Healthy Life Extension Society
and
IBIMA - Institute for Biostatistics and Informatics in Medicine and Ageing Research

