Source code for tooluniverse.rcsb_advanced_search_tool

# rcsb_advanced_search_tool.py
"""
RCSB PDB Advanced Search Tool for ToolUniverse.

Provides attribute-based filtering of PDB structures using the RCSB Search API v2.
Supports filtering by organism, resolution, experimental method, molecular weight,
polymer description, and deposition date. Goes beyond simple text/sequence search
to enable complex multi-criterion structure discovery.

API: https://search.rcsb.org/
No authentication required. Free public access.
"""

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

RCSB_SEARCH_URL = "https://search.rcsb.org/rcsbsearch/v2/query"


[docs] @register_tool("RCSBAdvancedSearchTool") class RCSBAdvancedSearchTool(BaseTool): """ Advanced attribute-based search of the RCSB Protein Data Bank. Enables complex queries combining organism, resolution, experimental method, molecular weight, and more. Returns PDB IDs matching all criteria. 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", "advanced_search")
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Execute the RCSB advanced search.""" try: return self._query(arguments) except requests.exceptions.Timeout: return {"error": f"RCSB Search API timed out after {self.timeout}s"} except requests.exceptions.ConnectionError: return {"error": "Failed to connect to RCSB Search API"} except requests.exceptions.HTTPError as e: msg = "" try: msg = e.response.json().get("message", "")[:200] except Exception: msg = str(e.response.status_code) return {"error": f"RCSB Search API error: {msg}"} except Exception as e: return {"error": f"Unexpected error: {str(e)}"}
[docs] def _query(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Route to appropriate endpoint.""" if self.endpoint == "advanced_search": return self._advanced_search(arguments) elif self.endpoint == "motif_search": return self._motif_search(arguments) else: return {"error": f"Unknown endpoint: {self.endpoint}"}