Source code for tooluniverse.lovd_tool
"""
LOVD (Leiden Open Variation Database) API tool for ToolUniverse.
LOVD is the world's largest open-source database system for DNA variants,
used by over 23,000 gene databases. The shared installation at
databases.lovd.nl/shared hosts curated variant data from gene-specific
databases including BRCA, TP53, and many other clinically relevant genes.
API: https://databases.lovd.nl/shared/api/rest.php/
Format: Atom XML by default, JSON with ?format=application/json
No authentication required.
"""
import requests
from typing import Any, Dict
from .base_tool import BaseTool
from .tool_registry import register_tool
LOVD_BASE_URL = "https://databases.lovd.nl/shared/api/rest.php"
[docs]
@register_tool("LOVDTool")
class LOVDTool(BaseTool):
"""
Tool for querying LOVD (Leiden Open Variation Database) REST API.
LOVD provides curated variant data including:
- Gene information (symbol, chromosomal location, RefSeq, curators)
- Variant details (DNA/RNA/protein notation, genomic position)
- Variant search by DBID or HGVS DNA notation
No authentication required.
"""
[docs]
def __init__(self, tool_config: Dict[str, Any]):
super().__init__(tool_config)
self.timeout = tool_config.get("timeout", 30)
self.operation = tool_config.get("fields", {}).get("operation", "get_gene")
[docs]
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute the LOVD API call."""
operation = self.operation
if operation == "get_gene":
return self._get_gene(arguments)
elif operation == "get_variants":
return self._get_variants(arguments)
elif operation == "search_variants":
return self._search_variants(arguments)
else:
return {"status": "error", "error": f"Unknown operation: {operation}"}
[docs]
def _make_request(self, url: str, params: dict = None) -> requests.Response:
"""Make a GET request with JSON format parameter."""
if params is None:
params = {}
params["format"] = "application/json"
response = requests.get(url, params=params, timeout=self.timeout)
return response
[docs]
def _get_gene(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get gene information from LOVD by gene symbol.
Returns gene details including HGNC ID, Entrez ID, chromosome location,
RefSeq transcripts, and curation information.
"""
gene_symbol = arguments.get("gene_symbol")
if not gene_symbol:
return {"status": "error", "error": "gene_symbol is required"}
gene_symbol = gene_symbol.strip().upper()
url = f"{LOVD_BASE_URL}/genes/{gene_symbol}"
try:
response = self._make_request(url)
if response.status_code == 404:
return {
"status": "error",
"error": f"Gene '{gene_symbol}' not found in LOVD",
}
response.raise_for_status()
data = response.json()
return {
"status": "success",
"data": data,
}
except requests.RequestException as e:
return {"status": "error", "error": f"LOVD API request failed: {str(e)}"}
[docs]
def _get_variants(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get variants for a gene from LOVD.
Returns all curated variants including DNA/RNA/protein notation,
genomic positions, and reporting counts. Use search_variants for
filtered queries.
"""
gene_symbol = arguments.get("gene_symbol")
if not gene_symbol:
return {"status": "error", "error": "gene_symbol is required"}
gene_symbol = gene_symbol.strip().upper()
url = f"{LOVD_BASE_URL}/variants/{gene_symbol}"
try:
response = self._make_request(url)
if response.status_code == 404:
return {
"status": "error",
"error": f"Gene '{gene_symbol}' not found in LOVD",
}
response.raise_for_status()
data = response.json()
# Warn if large result set
result = {
"status": "success",
"data": data,
}
if isinstance(data, list):
result["total_variants"] = len(data)
return result
except requests.RequestException as e:
return {"status": "error", "error": f"LOVD API request failed: {str(e)}"}
[docs]
def _search_variants(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Search variants in LOVD by DBID or DNA notation.
Supports searching by:
- Variant DBID (e.g., TP53_010464)
- DNA notation without RefSeq prefix (e.g., c.*2609C>A)
"""
gene_symbol = arguments.get("gene_symbol")
if not gene_symbol:
return {"status": "error", "error": "gene_symbol is required"}
gene_symbol = gene_symbol.strip().upper()
dbid = arguments.get("variant_dbid")
dna_notation = arguments.get("dna_notation")
if not dbid and not dna_notation:
return {
"status": "error",
"error": "Either variant_dbid or dna_notation is required",
}
url = f"{LOVD_BASE_URL}/variants/{gene_symbol}"
# Build search parameters
search_params = {}
if dbid:
search_params["search_Variant/DBID"] = dbid
elif dna_notation:
# LOVD expects notation without RefSeq prefix (e.g., c.742C>T)
search_params["search_Variant/DNA"] = dna_notation
try:
response = self._make_request(url, params=search_params)
if response.status_code == 404:
return {
"status": "error",
"error": f"Gene '{gene_symbol}' not found in LOVD",
}
response.raise_for_status()
data = response.json()
result = {
"status": "success",
"data": data,
}
if isinstance(data, list):
result["matches"] = len(data)
return result
except requests.RequestException as e:
return {"status": "error", "error": f"LOVD API request failed: {str(e)}"}