Source code for tooluniverse.mobidb_tool
# mobidb_tool.py
"""
MobiDB tool for ToolUniverse.
MobiDB is a comprehensive database of protein disorder and mobility,
integrating curated data from DisProt, predicted disorder from MobiDB-lite,
and structural data from PDB to provide a consensus view of intrinsically
disordered regions, linear interacting peptides (LIPs), and binding modes.
API: https://mobidb.org/api/download
No authentication required.
"""
import requests
from typing import Dict, Any
from .base_tool import BaseTool
from .tool_registry import register_tool
MOBIDB_BASE_URL = "https://mobidb.bio.unipd.it/api/download"
[docs]
@register_tool("MobiDBTool")
class MobiDBTool(BaseTool):
"""
Tool for querying MobiDB protein disorder database.
Supports:
- Get protein disorder predictions, curated regions, PTMs, binding modes
- Get consensus disorder summary for a protein
No authentication required.
"""
[docs]
def __init__(self, tool_config: Dict[str, Any]):
super().__init__(tool_config)
self.timeout = tool_config.get("timeout", 60)
fields = tool_config.get("fields", {})
self.endpoint = fields.get("endpoint", "get_protein")
[docs]
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute the MobiDB API call."""
try:
return self._query(arguments)
except requests.exceptions.Timeout:
return {"error": f"MobiDB API timed out after {self.timeout}s."}
except requests.exceptions.ConnectionError:
return {"error": "Failed to connect to MobiDB API (mobidb.bio.unipd.it)."}
except requests.exceptions.HTTPError as e:
status = e.response.status_code if e.response is not None else "unknown"
if status == 404:
return {
"error": "Protein not found in MobiDB. Check the UniProt accession."
}
return {"error": f"MobiDB API HTTP {status}"}
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 == "get_protein":
return self._get_protein(arguments)
elif self.endpoint == "get_consensus":
return self._get_consensus(arguments)
else:
return {"error": f"Unknown endpoint: {self.endpoint}"}
[docs]
def _get_protein(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Get comprehensive disorder data for a protein from MobiDB."""
accession = arguments.get("accession", "")
if not accession:
return {
"error": "accession is required (UniProt ID, e.g., 'P04637' for TP53)."
}
url = MOBIDB_BASE_URL
params = {"acc": accession, "format": "json"}
response = requests.get(
url, params=params, allow_redirects=True, timeout=self.timeout
)
response.raise_for_status()
data = response.json()
# Extract key disorder data
prediction = data.get("prediction-disorder-mobidb_lite", {})
curated_disorder = data.get("curated-disorder-disprot", {})
curated_lip = data.get("curated-lip-disprot", {})
# Extract PTM info
ptms = data.get("ptms", {})
ptm_summary = {}
if isinstance(ptms, dict):
ptm_names = ptms.get("names", [])
ptm_positions = ptms.get("positions", [])
ptm_summary = {
"count": len(ptm_positions) if isinstance(ptm_positions, list) else 0,
"types": ptm_names[:10] if isinstance(ptm_names, list) else [],
}
return {
"data": {
"accession": data.get("acc"),
"gene": data.get("gene"),
"name": data.get("name"),
"organism": data.get("organism"),
"length": data.get("length"),
"sequence": data.get("sequence"),
"prediction_disorder": {
"regions": prediction.get("regions", []),
"content_fraction": prediction.get("content_fraction"),
"content_count": prediction.get("content_count"),
},
"curated_disorder": {
"regions": curated_disorder.get("regions", []),
"content_count": curated_disorder.get("content_count"),
},
"curated_lip": {
"regions": curated_lip.get("regions", []),
"content_count": curated_lip.get("content_count"),
},
"ptm_summary": ptm_summary,
"localization": data.get("localization", []),
},
"metadata": {
"source": "MobiDB (mobidb.org)",
"reviewed": data.get("reviewed"),
},
}
[docs]
def _get_consensus(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Get consensus disorder summary for a protein."""
accession = arguments.get("accession", "")
if not accession:
return {
"error": "accession is required (UniProt ID, e.g., 'P04637' for TP53)."
}
url = MOBIDB_BASE_URL
params = {"acc": accession, "format": "json"}
response = requests.get(
url, params=params, allow_redirects=True, timeout=self.timeout
)
response.raise_for_status()
data = response.json()
# Extract consensus disorder data
consensus_disorder = data.get("prediction-disorder-mobidb_lite", {})
curated_merge = data.get("curated-disorder-merge", {})
phase_sep = data.get("curated-phase_separation-priority", {})
# Collect all binding mode info
binding_modes = {}
for key in data:
if key.startswith("curated-binding_mode"):
bm_data = data[key]
if isinstance(bm_data, dict) and bm_data.get("regions"):
binding_modes[key] = {
"regions": bm_data.get("regions", []),
"content_count": bm_data.get("content_count"),
}
return {
"data": {
"accession": data.get("acc"),
"gene": data.get("gene"),
"name": data.get("name"),
"organism": data.get("organism"),
"length": data.get("length"),
"predicted_disorder": {
"regions": consensus_disorder.get("regions", []),
"content_fraction": consensus_disorder.get("content_fraction"),
},
"curated_disorder_merged": {
"regions": curated_merge.get("regions", []),
},
"phase_separation": {
"regions": phase_sep.get("regions", []),
},
"binding_modes": binding_modes,
},
"metadata": {
"source": "MobiDB (mobidb.org)",
},
}