Source code for tooluniverse.ebi_taxonomy_tool

# ebi_taxonomy_tool.py
"""
EBI Taxonomy REST API tool for ToolUniverse.

The EBI Taxonomy service provides access to the NCBI Taxonomy database
through a RESTful interface. It supports lookup by taxonomy ID, scientific
name, common name, and provides name suggestions for search/submission.

API: https://www.ebi.ac.uk/ena/taxonomy/rest
No authentication required.
"""

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

EBI_TAXONOMY_BASE = "https://www.ebi.ac.uk/ena/taxonomy/rest"


[docs] @register_tool("EBITaxonomyTool") class EBITaxonomyTool(BaseTool): """ Tool for querying the EBI Taxonomy REST API. Provides taxonomy lookup by ID, scientific name, common/any name, and name suggestion for search or submission. Returns taxonomic classification including lineage, rank, division, and genetic codes. No authentication required. """
[docs] def __init__(self, tool_config: Dict[str, Any]): super().__init__(tool_config) self.timeout = tool_config.get("timeout", 30) self.endpoint_type = tool_config.get("fields", {}).get( "endpoint_type", "tax_by_id" )
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Execute the EBI Taxonomy API call.""" try: return self._query(arguments) except requests.exceptions.Timeout: return { "error": f"EBI Taxonomy API request timed out after {self.timeout}s" } except requests.exceptions.ConnectionError: return { "error": "Failed to connect to EBI Taxonomy API. Check network connectivity." } except requests.exceptions.HTTPError as e: return {"error": f"EBI Taxonomy API HTTP error: {e.response.status_code}"} except Exception as e: return {"error": f"Unexpected error querying EBI Taxonomy: {str(e)}"}
[docs] def _query(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Route to the appropriate EBI Taxonomy endpoint.""" endpoint_type = self.endpoint_type if endpoint_type == "tax_by_id": return self._get_by_tax_id(arguments) elif endpoint_type == "tax_by_scientific_name": return self._get_by_scientific_name(arguments) elif endpoint_type == "tax_by_any_name": return self._get_by_any_name(arguments) elif endpoint_type == "tax_suggest": return self._get_suggestions(arguments) else: return {"error": f"Unknown endpoint type: {endpoint_type}"}
[docs] def _get_by_tax_id(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Get taxonomy information by NCBI Taxonomy ID.""" tax_id = arguments.get("tax_id", "") if not tax_id: return {"error": "tax_id parameter is required"} url = f"{EBI_TAXONOMY_BASE}/tax-id/{tax_id}" response = requests.get( url, headers={"Accept": "application/json"}, timeout=self.timeout ) response.raise_for_status() data = response.json() return { "data": { "tax_id": data.get("taxId"), "scientific_name": data.get("scientificName"), "common_name": data.get("commonName"), "rank": data.get("rank"), "division": data.get("division"), "lineage": data.get("lineage"), "genetic_code": data.get("geneticCode"), "mitochondrial_genetic_code": data.get("mitochondrialGeneticCode"), "authority": data.get("authority"), "other_names": data.get("otherNames", []), "submittable": data.get("submittable"), "binomial": data.get("binomial"), "formal_name": data.get("formalName"), }, "metadata": { "query_tax_id": str(tax_id), "source": "EBI Taxonomy REST API", }, }
[docs] def _get_by_scientific_name(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Get taxonomy information by scientific name.""" name = arguments.get("scientific_name", "") if not name: return {"error": "scientific_name parameter is required"} url = f"{EBI_TAXONOMY_BASE}/scientific-name/{name}" response = requests.get( url, headers={"Accept": "application/json"}, timeout=self.timeout ) response.raise_for_status() data = response.json() results = data if isinstance(data, list) else [data] items = [] for item in results: items.append( { "tax_id": item.get("taxId"), "scientific_name": item.get("scientificName"), "common_name": item.get("commonName"), "rank": item.get("rank"), "division": item.get("division"), "lineage": item.get("lineage"), "genetic_code": item.get("geneticCode"), "authority": item.get("authority"), } ) return { "data": items, "metadata": { "total_results": len(items), "query_name": name, "source": "EBI Taxonomy REST API", }, }
[docs] def _get_by_any_name(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Get taxonomy by any name (scientific, common, synonym).""" name = arguments.get("name", "") if not name: return {"error": "name parameter is required"} url = f"{EBI_TAXONOMY_BASE}/any-name/{name}" response = requests.get( url, headers={"Accept": "application/json"}, timeout=self.timeout ) response.raise_for_status() data = response.json() results = data if isinstance(data, list) else [data] items = [] for item in results: items.append( { "tax_id": item.get("taxId"), "scientific_name": item.get("scientificName"), "common_name": item.get("commonName"), "rank": item.get("rank"), "division": item.get("division"), "lineage": item.get("lineage"), "authority": item.get("authority"), } ) return { "data": items, "metadata": { "total_results": len(items), "query_name": name, "source": "EBI Taxonomy REST API", }, }
[docs] def _get_suggestions(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Get taxonomy name suggestions for search.""" query = arguments.get("query", "") if not query: return {"error": "query parameter is required"} url = f"{EBI_TAXONOMY_BASE}/suggest-for-search/{query}" response = requests.get( url, headers={"Accept": "application/json"}, timeout=self.timeout ) response.raise_for_status() data = response.json() results = data if isinstance(data, list) else [data] items = [] for item in results: items.append( { "tax_id": item.get("taxId"), "scientific_name": item.get("scientificName"), "common_name": item.get("commonName"), "rank": item.get("rank"), "display_name": item.get("displayName"), } ) return { "data": items, "metadata": { "total_results": len(items), "query": query, "source": "EBI Taxonomy REST API", }, }