Source code for tooluniverse.alphafold_tool
import requests
import re
from typing import Dict, Any, List
from .base_tool import BaseTool
from .tool_registry import register_tool
ALPHAFOLD_BASE_URL = "https://alphafold.ebi.ac.uk/api"
[docs]
@register_tool("AlphaFoldRESTTool")
class AlphaFoldRESTTool(BaseTool):
"""
AlphaFold Protein Structure Database API tool.
Generic wrapper for AlphaFold API endpoints defined in alphafold_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["endpoint"]
self.required: List[str] = parameter.get("required", [])
self.output_format: str = fields.get("return_format", "JSON")
[docs]
def _build_url(self, arguments: Dict[str, Any]) -> str | Dict[str, Any]:
# Example: endpoint_template = "/annotations/{qualifier}.json"
url_path = self.endpoint_template
# Find placeholders like {qualifier} in the path
placeholders = re.findall(r"\{([^{}]+)\}", url_path)
used = set()
# Replace placeholders with provided arguments
# ex. if arguments = {"qualifier": "P69905", "type": "MUTAGEN"}
for ph in placeholders:
if ph not in arguments or arguments[ph] is None:
return {"error": f"Missing required parameter '{ph}'"}
url_path = url_path.replace(f"{{{ph}}}", str(arguments[ph]))
used.add(ph)
# Now url_path = "/annotations/P69905.json"
# Treat all remaining args as query parameters
# "type" wasn’t a placeholder, so it becomes a query param
query_args = {k: v for k, v in arguments.items() if k not in used}
if query_args:
from urllib.parse import urlencode
url_path += "?" + urlencode(query_args)
# Final result = "https://alphafold.ebi.ac.uk/api/annotations/P69905.json?type=MUTAGEN"
return ALPHAFOLD_BASE_URL + url_path
[docs]
def _make_request(self, url: str) -> Dict[str, Any]:
"""Perform a GET request and handle common errors."""
try:
resp = requests.get(
url,
timeout=30,
headers={
"Accept": "application/json",
"User-Agent": "ToolUniverse/AlphaFold",
},
)
except Exception as e:
return {"error": "Request to AlphaFold API failed", "detail": str(e)}
if resp.status_code == 404:
return {"error": "Not found", "endpoint": url}
if resp.status_code != 200:
return {
"error": f"AlphaFold API returned {resp.status_code}",
"detail": resp.text,
"endpoint": url,
}
return {"response": resp}
[docs]
def run(self, arguments: Dict[str, Any]):
"""Execute the tool with provided arguments."""
# Validate required params
missing = [k for k in self.required if k not in arguments]
if missing:
return {"error": f"Missing required parameter(s): {', '.join(missing)}"}
# Build URL
url = self._build_url(arguments)
if isinstance(url, dict) and "error" in url:
return {**url, "query": arguments}
# Make request
result = self._make_request(url)
if "error" in result:
return {**result, "query": arguments}
resp = result["response"]
# Parse JSON
if self.output_format.upper() == "JSON":
try:
data = resp.json()
if not data:
return {
"error": "AlphaFold returned an empty response",
"endpoint": url,
"query": arguments,
}
return {
"data": data,
"metadata": {
"count": len(data) if isinstance(data, list) else 1,
"source": "AlphaFold Protein Structure DB",
"endpoint": url,
"query": arguments,
},
}
except Exception as e:
return {
"error": "Failed to parse JSON response",
"raw": resp.text,
"detail": str(e),
"endpoint": url,
"query": arguments,
}
# Fallback for non-JSON output
return {"data": resp.text, "metadata": {"endpoint": url, "query": arguments}}