Source code for tooluniverse.pdbtm_tool

# pdbtm_tool.py
"""
PDBTM (Protein Data Bank of Transmembrane Proteins) tool for ToolUniverse.

PDBTM classifies transmembrane topology directly from solved PDB
structures: for each chain, whether it is alpha-helical, beta-barrel, or
not membrane-embedded, and how many transmembrane segments it has.

ToolUniverse already has OPM (membrane placement geometry and transfer
energy) and TopDB (curated per-region topology from experimental evidence).
PDBTM adds the third, independent view: per-chain classification computed
directly from structure coordinates, useful for cross-checking multi-chain
complexes chain by chain (e.g. which subunit of a photosynthetic reaction
centre is membrane-embedded and which is not).

API: https://pdbtm.unitmp.org/api/v1
No authentication required.
"""

from typing import Dict, Any, List

import requests

from .base_tool import BaseTool
from .tool_registry import register_tool

PDBTM_BASE_URL = "https://pdbtm.unitmp.org/api/v1"


[docs] @register_tool("PDBTMTool") class PDBTMTool(BaseTool): """ Tool for retrieving structure-derived transmembrane classification from PDBTM. Supports fetching one PDB entry's per-chain topology: whether each chain is alpha-helical, beta-barrel, or not membrane-embedded, and its transmembrane segment count. No authentication required. """
[docs] def __init__(self, tool_config: Dict[str, Any]): super().__init__(tool_config) self.timeout = tool_config.get("timeout", 45) self.operation = tool_config.get("fields", {}).get( "operation", "get_topology" )
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Execute the PDBTM lookup.""" try: if self.operation == "get_topology": return self._get_topology(arguments) return { "status": "error", "error": f"Unknown operation: {self.operation}", } except requests.exceptions.Timeout: return { "status": "error", "error": f"PDBTM request timed out after {self.timeout}s", } except requests.exceptions.ConnectionError: return { "status": "error", "error": "Failed to connect to PDBTM. Check network.", } except requests.exceptions.HTTPError as e: code = e.response.status_code if e.response is not None else "unknown" return {"status": "error", "error": f"PDBTM returned HTTP {code}"} except ValueError: return {"status": "error", "error": "PDBTM returned a non-JSON response"} except Exception as e: return {"status": "error", "error": f"Error querying PDBTM: {str(e)}"}
[docs] def _get_topology(self, arguments: Dict[str, Any]) -> Dict[str, Any]: """Fetch per-chain transmembrane classification for one PDB entry.""" pdb_id = (arguments.get("pdb_id") or "").strip().lower() if not pdb_id: return { "status": "error", "error": "pdb_id is required, e.g. '1prc' (photosynthetic " "reaction centre) or '2por' (porin).", } response = requests.get( f"{PDBTM_BASE_URL}/entry/{pdb_id}.json", timeout=self.timeout ) if response.status_code != 200: return { "status": "error", "error": f"No PDBTM entry for '{pdb_id}'. PDBTM only covers " "PDB structures it has classified as membrane proteins.", } payload = response.json() if not isinstance(payload, dict) or not payload.get("pdb_id"): return { "status": "error", "error": f"No PDBTM entry for '{pdb_id}'.", } chains: List[Dict[str, Any]] = [] for chain in payload.get("chains") or []: annotations = chain.get("additional_chain_annotations") or {} tm_type = annotations.get("type") num_tm = annotations.get("num_tm") chains.append( { "chain_label": chain.get("chain_label"), "tm_type": tm_type, "num_tm_segments": int(num_tm) if num_tm is not None else None, "is_membrane_embedded": tm_type not in (None, "non_tm"), } ) membrane = (payload.get("additional_entry_annotations") or {}).get( "membrane" ) or {} return { "status": "success", "data": { "pdb_id": payload.get("pdb_id"), "release_date": payload.get("release_date"), "chains": chains, "membrane_radius_angstrom": membrane.get("radius"), }, "metadata": { "pdb_id": pdb_id, "chain_count": len(chains), "note": "tm_type is 'alpha', 'beta', or 'non_tm'. Compare " "with OPM_search_structures (geometry/energetics) or " "TopDB_get_topology (curated per-region evidence).", "source": "PDBTM (Protein Data Bank of Transmembrane Proteins)", }, }