Files
gh-k-dense-ai-claude-scient…/skills/drugbank-database/scripts/drugbank_helper.py
2025-11-30 08:30:10 +08:00

351 lines
12 KiB
Python

#!/usr/bin/env python3
"""
DrugBank Helper Functions
Utility functions for common DrugBank operations including:
- Drug information extraction
- Interaction analysis
- Target identification
- Chemical property extraction
Usage:
from drugbank_helper import DrugBankHelper
db = DrugBankHelper()
drug_info = db.get_drug_info('DB00001')
interactions = db.get_interactions('DB00001')
"""
from typing import Dict, List, Optional, Any
import xml.etree.ElementTree as ET
class DrugBankHelper:
"""Helper class for DrugBank data access and analysis"""
NAMESPACE = {'db': 'http://www.drugbank.ca'}
def __init__(self, root=None):
"""
Initialize DrugBankHelper
Args:
root: Pre-loaded XML root element. If None, will load from drugbank-downloader
"""
self.root = root
self._drug_cache = {}
def _get_root(self):
"""Lazy load DrugBank root element"""
if self.root is None:
from drugbank_downloader import get_drugbank_root
self.root = get_drugbank_root()
return self.root
def _get_text_safe(self, element) -> Optional[str]:
"""Safely extract text from XML element"""
return element.text if element is not None else None
def find_drug(self, drugbank_id: str):
"""
Find drug element by DrugBank ID
Args:
drugbank_id: DrugBank ID (e.g., 'DB00001')
Returns:
XML element for the drug or None if not found
"""
if drugbank_id in self._drug_cache:
return self._drug_cache[drugbank_id]
root = self._get_root()
for drug in root.findall('db:drug', self.NAMESPACE):
primary_id = drug.find('db:drugbank-id[@primary="true"]', self.NAMESPACE)
if primary_id is not None and primary_id.text == drugbank_id:
self._drug_cache[drugbank_id] = drug
return drug
return None
def get_drug_info(self, drugbank_id: str) -> Dict[str, Any]:
"""
Get comprehensive drug information
Args:
drugbank_id: DrugBank ID
Returns:
Dictionary with drug information including name, type, description, etc.
"""
drug = self.find_drug(drugbank_id)
if drug is None:
return {}
info = {
'drugbank_id': drugbank_id,
'name': self._get_text_safe(drug.find('db:name', self.NAMESPACE)),
'type': drug.get('type'),
'description': self._get_text_safe(drug.find('db:description', self.NAMESPACE)),
'cas_number': self._get_text_safe(drug.find('db:cas-number', self.NAMESPACE)),
'indication': self._get_text_safe(drug.find('db:indication', self.NAMESPACE)),
'pharmacodynamics': self._get_text_safe(drug.find('db:pharmacodynamics', self.NAMESPACE)),
'mechanism_of_action': self._get_text_safe(drug.find('db:mechanism-of-action', self.NAMESPACE)),
}
return info
def get_interactions(self, drugbank_id: str) -> List[Dict[str, str]]:
"""
Get all drug-drug interactions
Args:
drugbank_id: DrugBank ID
Returns:
List of interaction dictionaries
"""
drug = self.find_drug(drugbank_id)
if drug is None:
return []
interactions = []
ddi_elem = drug.find('db:drug-interactions', self.NAMESPACE)
if ddi_elem is not None:
for interaction in ddi_elem.findall('db:drug-interaction', self.NAMESPACE):
interactions.append({
'partner_id': self._get_text_safe(interaction.find('db:drugbank-id', self.NAMESPACE)),
'partner_name': self._get_text_safe(interaction.find('db:name', self.NAMESPACE)),
'description': self._get_text_safe(interaction.find('db:description', self.NAMESPACE)),
})
return interactions
def get_targets(self, drugbank_id: str) -> List[Dict[str, Any]]:
"""
Get drug targets
Args:
drugbank_id: DrugBank ID
Returns:
List of target dictionaries
"""
drug = self.find_drug(drugbank_id)
if drug is None:
return []
targets = []
targets_elem = drug.find('db:targets', self.NAMESPACE)
if targets_elem is not None:
for target in targets_elem.findall('db:target', self.NAMESPACE):
target_data = {
'id': self._get_text_safe(target.find('db:id', self.NAMESPACE)),
'name': self._get_text_safe(target.find('db:name', self.NAMESPACE)),
'organism': self._get_text_safe(target.find('db:organism', self.NAMESPACE)),
'known_action': self._get_text_safe(target.find('db:known-action', self.NAMESPACE)),
}
# Extract actions
actions_elem = target.find('db:actions', self.NAMESPACE)
if actions_elem is not None:
target_data['actions'] = [
action.text for action in actions_elem.findall('db:action', self.NAMESPACE)
]
# Extract polypeptide info
polypeptide = target.find('db:polypeptide', self.NAMESPACE)
if polypeptide is not None:
target_data['uniprot_id'] = polypeptide.get('id')
target_data['gene_name'] = self._get_text_safe(
polypeptide.find('db:gene-name', self.NAMESPACE)
)
targets.append(target_data)
return targets
def get_properties(self, drugbank_id: str) -> Dict[str, Dict[str, Any]]:
"""
Get chemical properties
Args:
drugbank_id: DrugBank ID
Returns:
Dictionary with 'calculated' and 'experimental' property dictionaries
"""
drug = self.find_drug(drugbank_id)
if drug is None:
return {'calculated': {}, 'experimental': {}}
properties = {'calculated': {}, 'experimental': {}}
# Calculated properties
calc_props = drug.find('db:calculated-properties', self.NAMESPACE)
if calc_props is not None:
for prop in calc_props.findall('db:property', self.NAMESPACE):
kind = self._get_text_safe(prop.find('db:kind', self.NAMESPACE))
value = self._get_text_safe(prop.find('db:value', self.NAMESPACE))
if kind and value:
properties['calculated'][kind] = value
# Experimental properties
exp_props = drug.find('db:experimental-properties', self.NAMESPACE)
if exp_props is not None:
for prop in exp_props.findall('db:property', self.NAMESPACE):
kind = self._get_text_safe(prop.find('db:kind', self.NAMESPACE))
value = self._get_text_safe(prop.find('db:value', self.NAMESPACE))
if kind and value:
properties['experimental'][kind] = value
return properties
def check_interaction(self, drug1_id: str, drug2_id: str) -> Optional[Dict[str, str]]:
"""
Check if two drugs interact
Args:
drug1_id: First drug DrugBank ID
drug2_id: Second drug DrugBank ID
Returns:
Interaction dictionary if interaction exists, None otherwise
"""
interactions1 = self.get_interactions(drug1_id)
for interaction in interactions1:
if interaction['partner_id'] == drug2_id:
return interaction
# Check reverse direction
interactions2 = self.get_interactions(drug2_id)
for interaction in interactions2:
if interaction['partner_id'] == drug1_id:
return interaction
return None
def check_polypharmacy(self, drug_ids: List[str]) -> List[Dict[str, Any]]:
"""
Check interactions in a drug regimen
Args:
drug_ids: List of DrugBank IDs
Returns:
List of all interactions found between the drugs
"""
all_interactions = []
for i, drug1 in enumerate(drug_ids):
for drug2 in drug_ids[i + 1:]:
interaction = self.check_interaction(drug1, drug2)
if interaction:
interaction['drug1'] = drug1
interaction['drug2'] = drug2
all_interactions.append(interaction)
return all_interactions
def get_smiles(self, drugbank_id: str) -> Optional[str]:
"""
Get SMILES structure for a drug
Args:
drugbank_id: DrugBank ID
Returns:
SMILES string or None
"""
props = self.get_properties(drugbank_id)
return props.get('calculated', {}).get('SMILES')
def get_inchi(self, drugbank_id: str) -> Optional[str]:
"""
Get InChI structure for a drug
Args:
drugbank_id: DrugBank ID
Returns:
InChI string or None
"""
props = self.get_properties(drugbank_id)
return props.get('calculated', {}).get('InChI')
def search_by_name(self, name: str, exact: bool = False) -> List[Dict[str, str]]:
"""
Search drugs by name
Args:
name: Drug name to search for
exact: If True, require exact match (case-insensitive)
Returns:
List of matching drugs with id and name
"""
root = self._get_root()
results = []
search_term = name.lower()
for drug in root.findall('db:drug', self.NAMESPACE):
drug_id = drug.find('db:drugbank-id[@primary="true"]', self.NAMESPACE).text
drug_name = self._get_text_safe(drug.find('db:name', self.NAMESPACE))
if drug_name:
if exact:
if drug_name.lower() == search_term:
results.append({'id': drug_id, 'name': drug_name})
else:
if search_term in drug_name.lower():
results.append({'id': drug_id, 'name': drug_name})
return results
# Example usage
if __name__ == "__main__":
# Initialize helper
db = DrugBankHelper()
# Example: Get drug information
print("Example 1: Get drug information")
drug_info = db.get_drug_info('DB00001')
print(f"Drug: {drug_info.get('name')}")
print(f"Type: {drug_info.get('type')}")
print(f"Indication: {drug_info.get('indication', 'N/A')[:100]}...")
print()
# Example: Get interactions
print("Example 2: Get drug interactions")
interactions = db.get_interactions('DB00001')
print(f"Found {len(interactions)} interactions")
if interactions:
print(f"First interaction: {interactions[0]['partner_name']}")
print()
# Example: Get targets
print("Example 3: Get drug targets")
targets = db.get_targets('DB00001')
print(f"Found {len(targets)} targets")
if targets:
print(f"First target: {targets[0]['name']}")
print()
# Example: Check drug pair interaction
print("Example 4: Check specific drug pair")
interaction = db.check_interaction('DB00001', 'DB00002')
if interaction:
print("Interaction found!")
print(f"Description: {interaction['description'][:100]}...")
else:
print("No interaction found")
print()
# Example: Search by name
print("Example 5: Search drugs by name")
results = db.search_by_name('aspirin', exact=True)
if results:
print(f"Found: {results[0]['id']} - {results[0]['name']}")