Source code for tooluniverse.brenda_tool
"""
BRENDA Enzyme Database API tool for ToolUniverse.
BRENDA is the largest enzyme database containing functional data like
Km, Vmax, turnover numbers, and inhibitor information.
API: SPARQL endpoint at https://sparql.dsmz.de/brenda
No authentication required.
"""
import requests
from typing import Dict, Any, Optional, List
from .base_tool import BaseTool
from .tool_registry import register_tool
# BRENDA SPARQL endpoint (no auth required)
BRENDA_SPARQL_URL = "https://sparql.dsmz.de/brenda"
[docs]
@register_tool("BRENDATool")
class BRENDATool(BaseTool):
"""
Tool for querying BRENDA enzyme database.
BRENDA provides:
- Enzyme kinetic parameters (Km, kcat, Ki)
- Substrate/product information
- Enzyme inhibitors and activators
- Organism-specific data
Uses BRENDA SPARQL endpoint. No authentication required.
"""
[docs]
def __init__(self, tool_config: Dict[str, Any]):
super().__init__(tool_config)
self.timeout: int = tool_config.get("timeout", 60)
self.parameter = tool_config.get("parameter", {})
self.sparql_url = BRENDA_SPARQL_URL
[docs]
def _make_sparql_query(self, query: str) -> Dict[str, Any]:
"""Execute a SPARQL query against BRENDA endpoint."""
try:
response = requests.get(
self.sparql_url,
params={"query": query, "format": "json"},
headers={"Accept": "application/sparql-results+json"},
timeout=self.timeout,
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"SPARQL query failed: {str(e)}")
[docs]
def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Execute BRENDA API call based on operation type."""
operation = arguments.get("operation", "")
if operation == "get_km":
return self._get_km(arguments)
elif operation == "get_kcat":
return self._get_kcat(arguments)
elif operation == "get_inhibitors":
return self._get_inhibitors(arguments)
elif operation == "get_enzyme_info":
return self._get_enzyme_info(arguments)
else:
return {
"status": "error",
"error": f"Unknown operation: {operation}. Supported: get_km, get_kcat, get_inhibitors, get_enzyme_info",
}
[docs]
def _get_km(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get Km (Michaelis constant) values for an enzyme.
Args:
arguments: Dict containing:
- ec_number: EC number (e.g., 1.1.1.1 for alcohol dehydrogenase)
- organism: Optional organism filter
"""
ec_number = arguments.get("ec_number", "")
if not ec_number:
return {"status": "error", "error": "Missing required parameter: ec_number"}
organism = arguments.get("organism", "")
try:
# Build SPARQL query for Km values
organism_filter = (
f'FILTER(CONTAINS(LCASE(STR(?organism)), "{organism.lower()}"))'
if organism
else ""
)
query = f"""
PREFIX brenda: <http://brenda-enzymes.org/brenda/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?km ?substrate ?organism ?comment
WHERE {{
?enzyme brenda:ecNumber "{ec_number}" .
?enzyme brenda:kmValue ?kmEntry .
?kmEntry brenda:kmValue ?km .
OPTIONAL {{ ?kmEntry brenda:substrate ?substrate }}
OPTIONAL {{ ?kmEntry brenda:organism ?organism }}
OPTIONAL {{ ?kmEntry brenda:commentary ?comment }}
{organism_filter}
}}
LIMIT 100
"""
result = self._make_sparql_query(query)
# Parse SPARQL results
km_values = []
if "results" in result and "bindings" in result["results"]:
for binding in result["results"]["bindings"]:
km_values.append(
{
"km_value": binding.get("km", {}).get("value", ""),
"substrate": binding.get("substrate", {}).get("value", ""),
"organism": binding.get("organism", {}).get("value", ""),
"comment": binding.get("comment", {}).get("value", ""),
}
)
return {
"status": "success",
"data": {
"ec_number": ec_number,
"organism": organism if organism else "all",
"km_values": km_values,
"count": len(km_values),
},
"metadata": {
"source": "BRENDA SPARQL",
"parameter": "Km (Michaelis constant)",
"unit": "mM",
},
}
except Exception as e:
return {"status": "error", "error": f"BRENDA query failed: {str(e)}"}
[docs]
def _get_kcat(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get kcat (turnover number) values for an enzyme.
Args:
arguments: Dict containing:
- ec_number: EC number
- organism: Optional organism filter
"""
ec_number = arguments.get("ec_number", "")
if not ec_number:
return {"status": "error", "error": "Missing required parameter: ec_number"}
organism = arguments.get("organism", "")
try:
organism_filter = (
f'FILTER(CONTAINS(LCASE(STR(?organism)), "{organism.lower()}"))'
if organism
else ""
)
query = f"""
PREFIX brenda: <http://brenda-enzymes.org/brenda/>
SELECT ?kcat ?substrate ?organism ?comment
WHERE {{
?enzyme brenda:ecNumber "{ec_number}" .
?enzyme brenda:turnoverNumber ?kcatEntry .
?kcatEntry brenda:kcatValue ?kcat .
OPTIONAL {{ ?kcatEntry brenda:substrate ?substrate }}
OPTIONAL {{ ?kcatEntry brenda:organism ?organism }}
OPTIONAL {{ ?kcatEntry brenda:commentary ?comment }}
{organism_filter}
}}
LIMIT 100
"""
result = self._make_sparql_query(query)
kcat_values = []
if "results" in result and "bindings" in result["results"]:
for binding in result["results"]["bindings"]:
kcat_values.append(
{
"kcat_value": binding.get("kcat", {}).get("value", ""),
"substrate": binding.get("substrate", {}).get("value", ""),
"organism": binding.get("organism", {}).get("value", ""),
"comment": binding.get("comment", {}).get("value", ""),
}
)
return {
"status": "success",
"data": {
"ec_number": ec_number,
"organism": organism if organism else "all",
"kcat_values": kcat_values,
"count": len(kcat_values),
},
"metadata": {
"source": "BRENDA SPARQL",
"parameter": "kcat (turnover number)",
"unit": "1/s",
},
}
except Exception as e:
return {"status": "error", "error": f"BRENDA query failed: {str(e)}"}
[docs]
def _get_inhibitors(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get inhibitor data for an enzyme.
Args:
arguments: Dict containing:
- ec_number: EC number
- organism: Optional organism filter
"""
ec_number = arguments.get("ec_number", "")
if not ec_number:
return {"status": "error", "error": "Missing required parameter: ec_number"}
organism = arguments.get("organism", "")
try:
organism_filter = (
f'FILTER(CONTAINS(LCASE(STR(?organism)), "{organism.lower()}"))'
if organism
else ""
)
query = f"""
PREFIX brenda: <http://brenda-enzymes.org/brenda/>
SELECT ?inhibitor ?ki ?organism ?comment
WHERE {{
?enzyme brenda:ecNumber "{ec_number}" .
?enzyme brenda:inhibitor ?inhEntry .
?inhEntry brenda:inhibitorName ?inhibitor .
OPTIONAL {{ ?inhEntry brenda:kiValue ?ki }}
OPTIONAL {{ ?inhEntry brenda:organism ?organism }}
OPTIONAL {{ ?inhEntry brenda:commentary ?comment }}
{organism_filter}
}}
LIMIT 100
"""
result = self._make_sparql_query(query)
inhibitors = []
if "results" in result and "bindings" in result["results"]:
for binding in result["results"]["bindings"]:
inhibitors.append(
{
"inhibitor": binding.get("inhibitor", {}).get("value", ""),
"ki_value": binding.get("ki", {}).get("value", ""),
"organism": binding.get("organism", {}).get("value", ""),
"comment": binding.get("comment", {}).get("value", ""),
}
)
return {
"status": "success",
"data": {
"ec_number": ec_number,
"organism": organism if organism else "all",
"inhibitors": inhibitors,
"count": len(inhibitors),
},
"metadata": {
"source": "BRENDA SPARQL",
"parameter": "Inhibitors and Ki values",
"unit": "mM",
},
}
except Exception as e:
return {"status": "error", "error": f"BRENDA query failed: {str(e)}"}
[docs]
def _get_enzyme_info(self, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Get general enzyme information by EC number.
Args:
arguments: Dict containing:
- ec_number: EC number
"""
ec_number = arguments.get("ec_number", "")
if not ec_number:
return {"status": "error", "error": "Missing required parameter: ec_number"}
try:
query = f"""
PREFIX brenda: <http://brenda-enzymes.org/brenda/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?name ?systematicName ?reaction ?organism
WHERE {{
?enzyme brenda:ecNumber "{ec_number}" .
OPTIONAL {{ ?enzyme brenda:recommendedName ?name }}
OPTIONAL {{ ?enzyme brenda:systematicName ?systematicName }}
OPTIONAL {{ ?enzyme brenda:reaction ?reaction }}
OPTIONAL {{ ?enzyme brenda:organism ?organism }}
}}
LIMIT 10
"""
result = self._make_sparql_query(query)
enzyme_info = []
if "results" in result and "bindings" in result["results"]:
for binding in result["results"]["bindings"]:
enzyme_info.append(
{
"name": binding.get("name", {}).get("value", ""),
"systematic_name": binding.get("systematicName", {}).get(
"value", ""
),
"reaction": binding.get("reaction", {}).get("value", ""),
"organism": binding.get("organism", {}).get("value", ""),
}
)
return {
"status": "success",
"data": {
"ec_number": ec_number,
"info": enzyme_info
if enzyme_info
else [{"note": "Enzyme found but limited info available"}],
"count": len(enzyme_info),
},
"metadata": {
"source": "BRENDA SPARQL",
},
}
except Exception as e:
return {"status": "error", "error": f"BRENDA query failed: {str(e)}"}