Download test_integration.py from RottenShadow/ailixir-drug-repurposing: direct link, hf CLI and curl.
- Browser
- Download file 12.5 kB
-
https://huggingface.co/spaces/RottenShadow/ailixir-drug-repurposing/resolve/main/test_integration.py
- Command line
-
hf download hf://spaces/RottenShadow/ailixir-drug-repurposing/test_integration.py
-
curl -L -o test_integration.py https://huggingface.co/spaces/RottenShadow/ailixir-drug-repurposing/resolve/main/test_integration.py
12.5 kB
| #!/usr/bin/env python | |
| """ | |
| Integration Test Suite for Drug Repurposing API | |
| Tests all endpoints and verifies the entire pipeline works with real APIs | |
| Run with: python test_integration.py | |
| """ | |
| import requests | |
| import json | |
| import time | |
| from typing import Dict, Any, Tuple, Optional, List | |
| import sys | |
| # Configuration | |
| API_BASE_URL = "http://localhost:8000" | |
| TIMEOUT = 120 # 2 minutes timeout for screening | |
| class Colors: | |
| """Terminal colors""" | |
| GREEN = '\033[92m' | |
| RED = '\033[91m' | |
| YELLOW = '\033[93m' | |
| BLUE = '\033[94m' | |
| RESET = '\033[0m' | |
| def print_header(text: str): | |
| """Print a formatted header""" | |
| print(f"\n{Colors.BLUE}{'='*70}") | |
| print(f" {text}") | |
| print(f"{'='*70}{Colors.RESET}\n") | |
| def print_success(text: str): | |
| """Print success message""" | |
| print(f"{Colors.GREEN}β {text}{Colors.RESET}") | |
| def print_error(text: str): | |
| """Print error message""" | |
| print(f"{Colors.RED}β {text}{Colors.RESET}") | |
| def print_info(text: str): | |
| """Print info message""" | |
| print(f"{Colors.YELLOW}βΉοΈ {text}{Colors.RESET}") | |
| def test_health_check() -> bool: | |
| """Test health check endpoint""" | |
| print_header("Test 1: Health Check") | |
| try: | |
| response = requests.get(f"{API_BASE_URL}/health", timeout=10) | |
| if response.status_code == 200: | |
| data = response.json() | |
| print_success(f"API is healthy: {data['status']}") | |
| print(f" Version: {data['version']}") | |
| print(f" Service: {data['service']}") | |
| return True | |
| else: | |
| print_error(f"Health check failed with status {response.status_code}") | |
| return False | |
| except requests.exceptions.ConnectionError: | |
| print_error("Cannot connect to API. Is the server running on port 8000?") | |
| print_info("Start the server with: python -m uvicorn app.main:app --reload") | |
| return False | |
| except Exception as e: | |
| print_error(f"Health check error: {str(e)}") | |
| return False | |
| def test_model_status() -> bool: | |
| """Test model status endpoint""" | |
| print_header("Test 2: Model Status") | |
| try: | |
| response = requests.get(f"{API_BASE_URL}/api/v1/model-status", timeout=10) | |
| if response.status_code == 200: | |
| data = response.json() | |
| print_success("Model status retrieved:") | |
| print(f" Model: {data.get('model', 'N/A')}") | |
| print(f" Device: {data.get('device', 'N/A')}") | |
| print(f" GPU Available: {data.get('gpu_available', False)}") | |
| print(f" Model Loaded: {data.get('model_loaded', False)}") | |
| print(f" Using Mock: {data.get('using_mock_mode', False)}") | |
| print(f" Batch Size: {data.get('batch_size', 'N/A')}") | |
| print(f" Max Drugs: {data.get('max_drugs_per_screening', 'N/A')}") | |
| if not data.get('model_loaded') and data.get('using_mock_mode'): | |
| print_error("WARNING: DeepPurpose not loaded - using mock predictions") | |
| print_info("Install DeepPurpose for real predictions:") | |
| print_info(" pip install git+https://github.com/kexinhuang12345/DeepPurpose.git") | |
| return True | |
| else: | |
| print_error(f"Model status failed with status {response.status_code}") | |
| return False | |
| except Exception as e: | |
| print_error(f"Model status error: {str(e)}") | |
| return False | |
| def test_disease_targets() -> Tuple[bool, Optional[List[Dict]]]: | |
| """Test disease targets endpoint (Stage 1)""" | |
| print_header("Test 3: Disease Target Identification (OpenTargets)") | |
| disease = "Type 2 Diabetes" | |
| payload = { | |
| "disease_name": disease, | |
| "top_n": 5 | |
| } | |
| try: | |
| print_info(f"Searching for targets associated with: {disease}") | |
| response = requests.post( | |
| f"{API_BASE_URL}/api/v1/disease-targets", | |
| json=payload, | |
| timeout=30 | |
| ) | |
| if response.status_code == 200: | |
| data = response.json() | |
| print_success(f"Found {data['total_targets']} target proteins:") | |
| for i, target in enumerate(data['targets'][:3], 1): | |
| print(f" {i}. {target['symbol']} ({target['name']}) - Score: {target['score']}") | |
| if len(data['targets']) > 3: | |
| print(f" ... and {len(data['targets']) - 3} more") | |
| return True, data['targets'] | |
| else: | |
| print_error(f"Disease target search failed: {response.status_code}") | |
| print_error(f"Response: {response.text}") | |
| return False, None | |
| except requests.exceptions.Timeout: | |
| print_error(f"Request timeout - OpenTargets API slow or unavailable") | |
| return False, None | |
| except Exception as e: | |
| print_error(f"Disease targets error: {str(e)}") | |
| return False, None | |
| def test_protein_sequences(targets: Optional[List[Dict]]) -> Tuple[bool, Optional[List[Dict]]]: | |
| """Test protein sequences endpoint (Stage 2)""" | |
| print_header("Test 4: Protein Sequence Retrieval (UniProt)") | |
| if not targets or len(targets) == 0: | |
| print_error("No targets to test (skipping)") | |
| return False, None | |
| payload = targets[:3] # Test with first 3 targets | |
| try: | |
| print_info(f"Fetching sequences for {len(payload)} targets...") | |
| response = requests.post( | |
| f"{API_BASE_URL}/api/v1/protein-sequences", | |
| json=payload, | |
| timeout=30 | |
| ) | |
| if response.status_code == 200: | |
| data = response.json() | |
| print_success(f"Successfully fetched {data['total_found']} sequences:") | |
| for target in data['targets'][:2]: | |
| seq_len = len(target.get('sequence', '')) | |
| print(f" {target['symbol']}: {seq_len} amino acids") | |
| return True, data['targets'] | |
| else: | |
| print_error(f"Protein sequence fetch failed: {response.status_code}") | |
| return False, None | |
| except Exception as e: | |
| print_error(f"Protein sequences error: {str(e)}") | |
| return False, None | |
| def test_drug_library() -> Tuple[bool, Optional[List[Dict]]]: | |
| """Test drug library endpoint (Stage 3)""" | |
| print_header("Test 5: Drug Library Loading (TDC)") | |
| try: | |
| print_info("Loading drug library...") | |
| response = requests.get( | |
| f"{API_BASE_URL}/api/v1/drug-library", | |
| timeout=30 | |
| ) | |
| if response.status_code == 200: | |
| data = response.json() | |
| print_success(f"Loaded {data['total_drugs']} FDA-approved drugs:") | |
| for i, drug in enumerate(data['drugs'][:3], 1): | |
| print(f" {i}. {drug['name']} (ID: {drug.get('drug_id', 'N/A')})") | |
| print(f" SMILES: {drug['smiles'][:30]}...") | |
| if len(data['drugs']) > 3: | |
| print(f" ... and {len(data['drugs']) - 3} more") | |
| return True, data['drugs'] | |
| else: | |
| print_error(f"Drug library load failed: {response.status_code}") | |
| return False, None | |
| except Exception as e: | |
| print_error(f"Drug library error: {str(e)}") | |
| return False, None | |
| def test_virtual_screening() -> bool: | |
| """Test full virtual screening endpoint (All stages)""" | |
| print_header("Test 6: FULL VIRTUAL SCREENING PIPELINE") | |
| payload = { | |
| "disease_name": "Type 2 Diabetes", | |
| "min_score": 0.5, | |
| "top_n_targets": 5, | |
| "known_drugs": ["Metformin", "Insulin"] | |
| } | |
| print_info("This is the REAL END-TO-END PIPELINE:") | |
| print_info(" Stage 1: Disease targets (OpenTargets)") | |
| print_info(" Stage 2: Protein sequences (UniProt)") | |
| print_info(" Stage 3: Drug library (TDC)") | |
| print_info(" Stage 4: AI predictions (DeepPurpose)") | |
| print_info(" Stage 5: Result processing") | |
| print_info("") | |
| print_info(f"Request: {json.dumps(payload, indent=2)}") | |
| print_info("") | |
| print_info("β³ Running screening... (this may take 1-2 minutes)") | |
| start_time = time.time() | |
| try: | |
| response = requests.post( | |
| f"{API_BASE_URL}/api/v1/screen", | |
| json=payload, | |
| timeout=TIMEOUT | |
| ) | |
| elapsed = time.time() - start_time | |
| if response.status_code == 200: | |
| data = response.json() | |
| print_success(f"β SCREENING COMPLETE in {elapsed:.1f} seconds") | |
| print("") | |
| print(f"Disease Targeted: {data['disease']}") | |
| print(f"Targets Used: {data['total_targets_found']}") | |
| print(f"Drugs Screened: {data['total_drugs_screened']}") | |
| print(f"Total Predictions: {data['total_pairs_evaluated']}") | |
| print("") | |
| if data['top_candidates']: | |
| print_success(f"Top {len(data['top_candidates'])} candidates:") | |
| for i, result in enumerate(data['top_candidates'], 1): | |
| print(f" {i}. {result['drug_name']} β {result['target_symbol']}") | |
| print(f" Binding Score: {result['binding_score']:.3f} | {result['status']}") | |
| else: | |
| print_error("No results found") | |
| return True | |
| else: | |
| print_error(f"Screening failed: {response.status_code}") | |
| print_error(f"Response: {response.text}") | |
| return False | |
| except requests.exceptions.Timeout: | |
| elapsed = time.time() - start_time | |
| print_error(f"Request timeout after {elapsed:.1f} seconds") | |
| print_info("The screening took too long. This could be:") | |
| print_info(" 1. OpenTargets/UniProt APIs are slow") | |
| print_info(" 2. DeepPurpose is running on CPU (try GPU)") | |
| print_info(" 3. Network connection is slow") | |
| return False | |
| except Exception as e: | |
| print_error(f"Screening error: {str(e)}") | |
| return False | |
| def run_all_tests(): | |
| """Run all tests""" | |
| print(f"\n{Colors.BLUE}") | |
| print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") | |
| print("β 𧬠DRUG REPURPOSING API - COMPREHENSIVE TEST SUITE β") | |
| print("β Testing Production-Ready End-to-End Pipeline β") | |
| print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") | |
| print(f"{Colors.RESET}\n") | |
| results = [] | |
| # Test 1: Health | |
| results.append(("Health Check", test_health_check())) | |
| if not results[-1][1]: | |
| print_error("API is not responding. Make sure the server is running.") | |
| print_info("Start with: python -m uvicorn app.main:app --reload") | |
| return | |
| # Test 2: Model Status | |
| results.append(("Model Status", test_model_status())) | |
| # Test 3: Disease Targets | |
| success, targets = test_disease_targets() | |
| results.append(("Disease Targets", success)) | |
| # Test 4: Protein Sequences (requires targets) | |
| if targets: | |
| success, sequences = test_protein_sequences(targets) | |
| results.append(("Protein Sequences", success)) | |
| else: | |
| results.append(("Protein Sequences", False)) | |
| # Test 5: Drug Library | |
| success, drugs = test_drug_library() | |
| results.append(("Drug Library", success)) | |
| # Test 6: Full Pipeline | |
| results.append(("Full Virtual Screening", test_virtual_screening())) | |
| # Print summary | |
| print_header("TEST SUMMARY") | |
| passed = sum(1 for _, success in results if success) | |
| total = len(results) | |
| for test_name, success in results: | |
| status = f"{Colors.GREEN}β PASSED{Colors.RESET}" if success else f"{Colors.RED}β FAILED{Colors.RESET}" | |
| print(f"{test_name:.<50} {status}") | |
| print("") | |
| print_success(f"TOTAL: {passed}/{total} tests passed") | |
| if passed == total: | |
| print_success("π ALL TESTS PASSED! System is production-ready.") | |
| else: | |
| print_error(f"β οΈ {total - passed} test(s) failed. See details above.") | |
| print("") | |
| if __name__ == "__main__": | |
| try: | |
| run_all_tests() | |
| except KeyboardInterrupt: | |
| print_error("\nTests interrupted by user") | |
| sys.exit(1) | |
| except Exception as e: | |
| print_error(f"Test suite error: {str(e)}") | |
| sys.exit(1) | |