Source code for tooluniverse.string_tool
"""STRING Database REST API Tool for protein-protein interaction data."""
import requests
from typing import Any, Dict, List
from .base_tool import BaseTool
from .tool_registry import register_tool
STRING_BASE_URL = "https://string-db.org/api"
[docs]
@register_tool("STRINGRESTTool")
class STRINGRESTTool(BaseTool):
"""STRING Database REST API tool.
Generic wrapper for STRING API endpoints defined in ppi_tools.json.
"""
[docs]
def __init__(self, tool_config):
super().__init__(tool_config)
fields = tool_config.get("fields", {})
parameter = tool_config.get("parameter", {})
self.endpoint_template: str = fields.get("endpoint", "/tsv/network")
self.required: List[str] = parameter.get("required", [])
self.output_format: str = fields.get("return_format", "TSV")
[docs]
def _build_url(self) -> str:
"""Build URL for STRING API request."""
return STRING_BASE_URL + self.endpoint_template
[docs]
def _build_params(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Build parameters for STRING API request."""
params = {}
# Map protein IDs to STRING format
if "protein_ids" in arguments:
protein_ids = arguments["protein_ids"]
if isinstance(protein_ids, list):
params["identifiers"] = "\r".join(protein_ids)
else:
params["identifiers"] = str(protein_ids)
# Add other parameters
if "species" in arguments:
params["species"] = arguments["species"]
if "confidence_score" in arguments:
params["required_score"] = int(arguments["confidence_score"] * 1000)
if "limit" in arguments:
params["limit"] = arguments["limit"]
if "network_type" in arguments:
params["network_type"] = arguments["network_type"]
# Additional parameters for other endpoints
if "caller_identity" in arguments:
params["caller_identity"] = arguments["caller_identity"]
if "echo_query" in arguments:
params["echo_query"] = arguments["echo_query"]
if "add_nodes" in arguments:
params["add_nodes"] = arguments["add_nodes"]
if "category" in arguments:
params["category"] = arguments["category"]
return params
[docs]
def _make_request(self, url: str, params: Dict[str, Any]) -> Dict[str, Any]:
"""Perform a GET request and handle common errors."""
try:
response = requests.get(url, params=params, timeout=30)
response.raise_for_status()
if self.output_format == "TSV":
return self._parse_tsv_response(response.text)
if self.output_format == "JSON":
return response.json()
try:
return response.json()
except (ValueError, KeyError):
return self._parse_tsv_response(response.text)
except requests.exceptions.RequestException as e:
return {"error": f"Request failed: {str(e)}"}
except Exception as e:
return {"error": f"Unexpected error: {str(e)}"}
[docs]
def _parse_tsv_response(self, text: str) -> Dict[str, Any]:
"""Parse TSV response from STRING API."""
lines = text.strip().split("\n")
if len(lines) < 2:
return {"data": [], "error": "No data returned"}
header = lines[0].split("\t")
data = [
dict(zip(header, line.split("\t"))) for line in lines[1:] if line.strip()
]
return {"data": data, "header": header}
[docs]
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute the tool with given arguments."""
for param in self.required:
if param not in arguments:
error_msg = f"Missing required parameter: {param}"
return {
"status": "error",
"data": {"error": error_msg},
"error": error_msg,
}
url = self._build_url()
params = self._build_params(arguments)
api_response = self._make_request(url, params)
if "error" in api_response:
return {
"status": "error",
"data": api_response,
"error": api_response.get("error"),
}
return {"status": "success", "data": api_response}