Source code for tooluniverse.ctd_tool

# ctd_tool.py
"""
CTD (Comparative Toxicogenomics Database) REST API tool for ToolUniverse.

CTD is a curated database that advances understanding about how environmental
exposures affect human health. It provides manually curated interactions between
chemicals, genes, phenotypes, diseases, and exposure data.

API: https://ctdbase.org/tools/batchQuery.go
No authentication required. Free for academic/research use.
"""

import requests
from typing import Dict, Any
from .base_tool import BaseTool
from .tool_registry import register_tool

CTD_BASE_URL = "https://ctdbase.org/tools/batchQuery.go"


[docs] @register_tool("CTDTool") class CTDTool(BaseTool): """ Tool for querying the Comparative Toxicogenomics Database (CTD). CTD curates chemical-gene, chemical-disease, and gene-disease relationships from peer-reviewed literature. Supports queries by chemical names, gene symbols, disease names, or their standard identifiers. No authentication required. """
[docs] def __init__(self, tool_config: Dict[str, Any]): super().__init__(tool_config) self.timeout = tool_config.get("timeout", 60) self.input_type = tool_config.get("fields", {}).get("input_type", "chem") self.report_type = tool_config.get("fields", {}).get( "report_type", "genes_curated" )
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Execute the CTD batch query API call.""" try: return self._query(arguments) except requests.exceptions.Timeout: return {"error": f"CTD API request timed out after {self.timeout} seconds"} except requests.exceptions.ConnectionError: return { "error": "Failed to connect to CTD API. Check network connectivity." } except requests.exceptions.HTTPError as e: return {"error": f"CTD API HTTP error: {e.response.status_code}"} except Exception as e: return {"error": f"Unexpected error querying CTD: {str(e)}"}
[docs] def _query(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Execute a CTD batch query and return structured results.""" input_terms = arguments.get("input_terms", "") if not input_terms: return {"error": "input_terms parameter is required"} # Allow overriding input_type and report_type from arguments input_type = arguments.get("input_type", self.input_type) report_type = arguments.get("report_type", self.report_type) params = { "inputType": input_type, "inputTerms": input_terms, "report": report_type, "format": "json", } response = requests.get(CTD_BASE_URL, params=params, timeout=self.timeout) response.raise_for_status() raw_text = response.text.strip() if not raw_text or raw_text == "[]": return { "data": [], "metadata": { "total_results": 0, "input_type": input_type, "report_type": report_type, "query": input_terms, }, } try: data = response.json() except ValueError: return {"error": "CTD API returned non-JSON response"} if isinstance(data, list): return { "data": data, "metadata": { "total_results": len(data), "input_type": input_type, "report_type": report_type, "query": input_terms, }, } elif isinstance(data, dict): return { "data": data, "metadata": { "total_results": 1, "input_type": input_type, "report_type": report_type, "query": input_terms, }, } else: return {"error": f"Unexpected CTD response type: {type(data).__name__}"}