Source code for tooluniverse.disease_ontology_tool

# disease_ontology_tool.py
"""
Disease Ontology (DO) REST API tool for ToolUniverse.

The Disease Ontology provides a standardized ontology for human disease terms.
It is widely used in bioinformatics for disease annotation and cross-referencing
with ICD-10, OMIM, MeSH, NCI Thesaurus, and SNOMED-CT.

API: https://www.disease-ontology.org/api/
No authentication required.
"""

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

DO_BASE_URL = "https://www.disease-ontology.org/api/metadata"


[docs] @register_tool("DiseaseOntologyTool") class DiseaseOntologyTool(BaseTool): """ Tool for querying the Disease Ontology (DO) REST API. The Disease Ontology semantically integrates disease and medical vocabularies through cross-mapping of DO terms to MeSH, ICD, NCI Thesaurus, SNOMED CT, and OMIM. Supports: term lookup, parent hierarchy navigation. No authentication required. """
[docs] def __init__(self, tool_config: Dict[str, Any]): super().__init__(tool_config) self.timeout = tool_config.get("timeout", 30) fields = tool_config.get("fields", {}) self.endpoint = fields.get("endpoint", "get_term")
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Execute the Disease Ontology API call.""" try: return self._query(arguments) except requests.exceptions.Timeout: return {"error": f"Disease Ontology API timed out after {self.timeout}s"} except requests.exceptions.ConnectionError: return {"error": "Failed to connect to Disease Ontology API"} except requests.exceptions.HTTPError as e: if e.response.status_code == 404: return {"error": f"DOID not found in Disease Ontology"} return { "error": f"Disease Ontology API HTTP error: {e.response.status_code}" } except Exception as e: return {"error": f"Unexpected error querying Disease Ontology: {str(e)}"}
[docs] def _query(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Route to appropriate Disease Ontology endpoint.""" if self.endpoint == "get_term": return self._get_term(arguments) elif self.endpoint == "get_parents": return self._get_parents(arguments) else: return {"error": f"Unknown endpoint: {self.endpoint}"}
[docs] def _fetch_term(self, doid: str) -> Dict[str, Any]: """Fetch a single DO term by DOID.""" # Extract numeric ID from DOID format if ":" in doid: numeric_id = doid.split(":")[1] else: numeric_id = doid url = f"{DO_BASE_URL}/DOID:{numeric_id}/" response = requests.get(url, timeout=self.timeout, allow_redirects=True) response.raise_for_status() return response.json()
[docs] def _get_term(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Get detailed information about a Disease Ontology term.""" doid = arguments.get("doid", "") if not doid: return {"error": "doid parameter is required"} data = self._fetch_term(doid) # Parse parents parents = [] for p in data.get("parents") or []: if isinstance(p, (list, tuple)) and len(p) >= 3: parents.append( { "relationship": p[0], "name": p[1], "id": p[2], } ) # Parse synonyms (format: "name TYPE []") synonyms = [] for s in data.get("synonyms") or []: synonyms.append(s) return { "data": { "id": data.get("id"), "name": data.get("name"), "definition": data.get("definition"), "synonyms": synonyms, "parents": parents, "cross_references": data.get("xrefs", []), "subsets": data.get("subsets", []), }, "metadata": { "source": "Disease Ontology (DO)", }, }
[docs] def _get_parents(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Get parent terms for a Disease Ontology term with hierarchy navigation.""" doid = arguments.get("doid", "") if not doid: return {"error": "doid parameter is required"} data = self._fetch_term(doid) parents_detail = [] for p in data.get("parents") or []: if isinstance(p, (list, tuple)) and len(p) >= 3: parent_id = p[2] try: parent_data = self._fetch_term(parent_id) grandparents = [] for gp in parent_data.get("parents") or []: if isinstance(gp, (list, tuple)) and len(gp) >= 3: grandparents.append( { "id": gp[2], "name": gp[1], } ) parents_detail.append( { "id": parent_id, "name": parent_data.get("name"), "definition": parent_data.get("definition"), "grandparents": grandparents, } ) except Exception: parents_detail.append( { "id": parent_id, "name": p[1], "definition": None, "grandparents": [], } ) return { "data": { "id": data.get("id"), "name": data.get("name"), "parents": parents_detail, }, "metadata": { "source": "Disease Ontology (DO)", }, }