boltz2-python-client 0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. boltz2_python_client-0.2/ASYNC_GUIDE.md +470 -0
  2. boltz2_python_client-0.2/COVALENT_COMPLEX_GUIDE.md +207 -0
  3. boltz2_python_client-0.2/INSTALL_TESTPYPI.md +122 -0
  4. boltz2_python_client-0.2/LICENSE +21 -0
  5. boltz2_python_client-0.2/MANIFEST.in +17 -0
  6. boltz2_python_client-0.2/PARAMETERS.md +554 -0
  7. boltz2_python_client-0.2/PKG-INFO +533 -0
  8. boltz2_python_client-0.2/README.md +497 -0
  9. boltz2_python_client-0.2/YAML_GUIDE.md +395 -0
  10. boltz2_python_client-0.2/boltz2_client/__init__.py +153 -0
  11. boltz2_python_client-0.2/boltz2_client/cli.py +1213 -0
  12. boltz2_python_client-0.2/boltz2_client/client.py +986 -0
  13. boltz2_python_client-0.2/boltz2_client/exceptions.py +213 -0
  14. boltz2_python_client-0.2/boltz2_client/models.py +466 -0
  15. boltz2_python_client-0.2/boltz2_client/models_affinity.py +46 -0
  16. boltz2_python_client-0.2/boltz2_client/utils.py +455 -0
  17. boltz2_python_client-0.2/boltz2_client/virtual_screening.py +608 -0
  18. boltz2_python_client-0.2/boltz2_python_client.egg-info/PKG-INFO +533 -0
  19. boltz2_python_client-0.2/boltz2_python_client.egg-info/SOURCES.txt +50 -0
  20. boltz2_python_client-0.2/boltz2_python_client.egg-info/dependency_links.txt +1 -0
  21. boltz2_python_client-0.2/boltz2_python_client.egg-info/entry_points.txt +2 -0
  22. boltz2_python_client-0.2/boltz2_python_client.egg-info/requires.txt +8 -0
  23. boltz2_python_client-0.2/boltz2_python_client.egg-info/top_level.txt +1 -0
  24. boltz2_python_client-0.2/examples/.ipynb_checkpoints/08_affinity_prediction-checkpoint.py +199 -0
  25. boltz2_python_client-0.2/examples/.ipynb_checkpoints/multi_endpoint_screening-checkpoint.py +204 -0
  26. boltz2_python_client-0.2/examples/01_basic_protein_folding.py +49 -0
  27. boltz2_python_client-0.2/examples/02_protein_structure_prediction_with_msa.py +186 -0
  28. boltz2_python_client-0.2/examples/03_protein_ligand_complex.py +237 -0
  29. boltz2_python_client-0.2/examples/04_covalent_bonding.py +199 -0
  30. boltz2_python_client-0.2/examples/05_dna_protein_complex.py +211 -0
  31. boltz2_python_client-0.2/examples/06_yaml_configurations.py +273 -0
  32. boltz2_python_client-0.2/examples/07_advanced_parameters.py +344 -0
  33. boltz2_python_client-0.2/examples/08_affinity_prediction_simple.py +106 -0
  34. boltz2_python_client-0.2/examples/09_virtual_screening.py +227 -0
  35. boltz2_python_client-0.2/examples/msa-kras-g12c_combined.a3m +1178 -0
  36. boltz2_python_client-0.2/examples/multi_protein_complex.yaml +10 -0
  37. boltz2_python_client-0.2/examples/protein_ligand.yaml +8 -0
  38. boltz2_python_client-0.2/examples/sars_cov2_mpro_nirmatrelvir.yaml +8 -0
  39. boltz2_python_client-0.2/licenses/PyYAML-LICENSE +22 -0
  40. boltz2_python_client-0.2/licenses/README.md +24 -0
  41. boltz2_python_client-0.2/licenses/aiofiles-LICENSE +17 -0
  42. boltz2_python_client-0.2/licenses/click-LICENSE +30 -0
  43. boltz2_python_client-0.2/licenses/httpx-LICENSE +29 -0
  44. boltz2_python_client-0.2/licenses/py3Dmol-LICENSE +21 -0
  45. boltz2_python_client-0.2/licenses/pydantic-LICENSE +21 -0
  46. boltz2_python_client-0.2/licenses/rich-LICENSE +21 -0
  47. boltz2_python_client-0.2/licenses/typing-extensions-LICENSE +109 -0
  48. boltz2_python_client-0.2/pyproject.toml +61 -0
  49. boltz2_python_client-0.2/setup.cfg +4 -0
  50. boltz2_python_client-0.2/tests/__init__.py +1 -0
  51. boltz2_python_client-0.2/tests/test_basic.py +167 -0
  52. boltz2_python_client-0.2/tests/test_examples_syntax.py +148 -0
@@ -0,0 +1,470 @@
1
+ # Async Programming Guide for Boltz-2 Python Client
2
+
3
+ Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
4
+
5
+ This guide demonstrates how to efficiently perform asynchronous protein structure predictions using the Boltz-2 Python client. Async programming allows you to process multiple protein sequences concurrently, dramatically improving throughput for batch operations.
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Basic Async Concepts](#basic-async-concepts)
10
+ 2. [Simple Async Example](#simple-async-example)
11
+ 3. [Batch Processing with Rate Limiting](#batch-processing-with-rate-limiting)
12
+ 4. [Advanced Patterns](#advanced-patterns)
13
+ 5. [Performance Optimization](#performance-optimization)
14
+ 6. [Error Handling](#error-handling)
15
+ 7. [Best Practices](#best-practices)
16
+
17
+ ## Basic Async Concepts
18
+
19
+ ### Why Use Async?
20
+
21
+ - **Concurrency**: Process multiple proteins simultaneously
22
+ - **Efficiency**: Better resource utilization during I/O operations
23
+ - **Scalability**: Handle large batches without blocking
24
+ - **Throughput**: Significantly faster than sequential processing
25
+
26
+ ### Key Components
27
+
28
+ ```python
29
+ import asyncio
30
+ from boltz2_client import Boltz2Client, EndpointType
31
+
32
+ # Create async client
33
+ client = Boltz2Client(
34
+ base_url="http://localhost:8000",
35
+ endpoint_type=EndpointType.LOCAL
36
+ )
37
+
38
+ # Async function
39
+ async def fold_protein(sequence: str):
40
+ response = await client.predict_protein_structure(
41
+ sequence=sequence,
42
+ recycling_steps=1,
43
+ sampling_steps=20,
44
+ save_structures=False
45
+ )
46
+ return response
47
+
48
+ # Run async function
49
+ result = asyncio.run(fold_protein("MKTVRQERLK..."))
50
+ ```
51
+
52
+ ## Simple Async Example
53
+
54
+ ### Single Protein (Async)
55
+
56
+ ```python
57
+ import asyncio
58
+ from boltz2_client import Boltz2Client
59
+
60
+ async def predict_single():
61
+ client = Boltz2Client("http://localhost:8000")
62
+
63
+ response = await client.predict_protein_structure(
64
+ sequence="MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG",
65
+ recycling_steps=3,
66
+ sampling_steps=50
67
+ )
68
+
69
+ print(f"Confidence: {response.confidence_scores[0]:.3f}")
70
+ return response
71
+
72
+ # Run it
73
+ result = asyncio.run(predict_single())
74
+ ```
75
+
76
+ ### Multiple Proteins (Concurrent)
77
+
78
+ ```python
79
+ import asyncio
80
+ from boltz2_client import Boltz2Client
81
+
82
+ async def predict_multiple():
83
+ client = Boltz2Client("http://localhost:8000")
84
+
85
+ sequences = [
86
+ "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG",
87
+ "MKLLVVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLV",
88
+ "ACDEFGHIKLMNPQRSTVWYACDEFGHIKLMNPQRSTVWYACDEFGHIKLMNPQRSTVWY"
89
+ ]
90
+
91
+ # Create tasks for concurrent execution
92
+ tasks = [
93
+ client.predict_protein_structure(
94
+ sequence=seq,
95
+ recycling_steps=1,
96
+ sampling_steps=20,
97
+ save_structures=False
98
+ )
99
+ for seq in sequences
100
+ ]
101
+
102
+ # Wait for all to complete
103
+ results = await asyncio.gather(*tasks)
104
+
105
+ for i, result in enumerate(results):
106
+ confidence = result.confidence_scores[0] if result.confidence_scores else 0
107
+ print(f"Protein {i+1}: confidence={confidence:.3f}")
108
+
109
+ return results
110
+
111
+ # Run it
112
+ results = asyncio.run(predict_multiple())
113
+ ```
114
+
115
+ ## Batch Processing with Rate Limiting
116
+
117
+ ### Using Semaphore for Rate Limiting
118
+
119
+ ```python
120
+ import asyncio
121
+ from boltz2_client import Boltz2Client
122
+
123
+ class RateLimitedFolder:
124
+ def __init__(self, max_concurrent=5):
125
+ self.client = Boltz2Client("http://localhost:8000")
126
+ self.semaphore = asyncio.Semaphore(max_concurrent)
127
+
128
+ async def fold_with_limit(self, sequence: str, protein_id: str):
129
+ async with self.semaphore: # Rate limiting
130
+ try:
131
+ response = await self.client.predict_protein_structure(
132
+ sequence=sequence,
133
+ recycling_steps=1,
134
+ sampling_steps=20,
135
+ save_structures=False
136
+ )
137
+ confidence = response.confidence_scores[0] if response.confidence_scores else 0
138
+ print(f"โœ… {protein_id}: confidence={confidence:.3f}")
139
+ return {"id": protein_id, "success": True, "confidence": confidence}
140
+ except Exception as e:
141
+ print(f"โŒ {protein_id}: {e}")
142
+ return {"id": protein_id, "success": False, "error": str(e)}
143
+
144
+ async def batch_fold():
145
+ folder = RateLimitedFolder(max_concurrent=3)
146
+
147
+ # Your protein sequences
148
+ proteins = [
149
+ ("protein_1", "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG"),
150
+ ("protein_2", "MKLLVVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLV"),
151
+ # ... more proteins
152
+ ]
153
+
154
+ tasks = [
155
+ folder.fold_with_limit(sequence, protein_id)
156
+ for protein_id, sequence in proteins
157
+ ]
158
+
159
+ results = await asyncio.gather(*tasks)
160
+ return results
161
+
162
+ # Run batch folding
163
+ results = asyncio.run(batch_fold())
164
+ ```
165
+
166
+ ## Advanced Patterns
167
+
168
+ ### Progress Tracking with asyncio.as_completed
169
+
170
+ ```python
171
+ import asyncio
172
+ import time
173
+ from boltz2_client import Boltz2Client
174
+
175
+ async def fold_with_progress(sequences):
176
+ client = Boltz2Client("http://localhost:8000")
177
+
178
+ # Create tasks
179
+ tasks = [
180
+ client.predict_protein_structure(
181
+ sequence=seq,
182
+ recycling_steps=1,
183
+ sampling_steps=20,
184
+ save_structures=False
185
+ )
186
+ for seq in sequences
187
+ ]
188
+
189
+ results = []
190
+ completed = 0
191
+ total = len(tasks)
192
+
193
+ # Process as they complete
194
+ for coro in asyncio.as_completed(tasks):
195
+ try:
196
+ result = await coro
197
+ confidence = result.confidence_scores[0] if result.confidence_scores else 0
198
+ results.append(result)
199
+ completed += 1
200
+
201
+ print(f"Progress: {completed}/{total} ({completed/total*100:.1f}%) - Latest confidence: {confidence:.3f}")
202
+
203
+ except Exception as e:
204
+ print(f"Error: {e}")
205
+ completed += 1
206
+
207
+ return results
208
+ ```
209
+
210
+ ### Retry Logic with Exponential Backoff
211
+
212
+ ```python
213
+ import asyncio
214
+ import random
215
+ from boltz2_client import Boltz2Client
216
+
217
+ async def fold_with_retry(client, sequence, max_retries=3):
218
+ for attempt in range(max_retries):
219
+ try:
220
+ response = await client.predict_protein_structure(
221
+ sequence=sequence,
222
+ recycling_steps=1,
223
+ sampling_steps=20,
224
+ save_structures=False
225
+ )
226
+ return response
227
+ except Exception as e:
228
+ if attempt < max_retries - 1:
229
+ delay = (2 ** attempt) + random.uniform(0, 1) # Exponential backoff
230
+ print(f"Attempt {attempt + 1} failed, retrying in {delay:.1f}s: {e}")
231
+ await asyncio.sleep(delay)
232
+ else:
233
+ print(f"All {max_retries} attempts failed: {e}")
234
+ raise
235
+ ```
236
+
237
+ ### Chunked Processing for Large Batches
238
+
239
+ ```python
240
+ import asyncio
241
+ from boltz2_client import Boltz2Client
242
+
243
+ async def process_in_chunks(sequences, chunk_size=10):
244
+ client = Boltz2Client("http://localhost:8000")
245
+ all_results = []
246
+
247
+ # Process sequences in chunks
248
+ for i in range(0, len(sequences), chunk_size):
249
+ chunk = sequences[i:i + chunk_size]
250
+ print(f"Processing chunk {i//chunk_size + 1}/{(len(sequences)-1)//chunk_size + 1}")
251
+
252
+ # Process chunk concurrently
253
+ tasks = [
254
+ client.predict_protein_structure(
255
+ sequence=seq,
256
+ recycling_steps=1,
257
+ sampling_steps=20,
258
+ save_structures=False
259
+ )
260
+ for seq in chunk
261
+ ]
262
+
263
+ chunk_results = await asyncio.gather(*tasks, return_exceptions=True)
264
+ all_results.extend(chunk_results)
265
+
266
+ # Brief pause between chunks
267
+ await asyncio.sleep(1)
268
+
269
+ return all_results
270
+ ```
271
+
272
+ ## Performance Optimization
273
+
274
+ ### Optimal Concurrency Settings
275
+
276
+ ```python
277
+ # Local endpoint - adjust based on GPU memory
278
+ MAX_CONCURRENT_LOCAL = 3-5
279
+
280
+ # NVIDIA hosted endpoint - respect rate limits
281
+ MAX_CONCURRENT_HOSTED = 10-20
282
+
283
+ # Fast settings for batch processing
284
+ FAST_SETTINGS = {
285
+ "recycling_steps": 1,
286
+ "sampling_steps": 20,
287
+ "save_structures": False
288
+ }
289
+
290
+ # High-quality settings for important predictions
291
+ QUALITY_SETTINGS = {
292
+ "recycling_steps": 3,
293
+ "sampling_steps": 50,
294
+ "save_structures": True
295
+ }
296
+ ```
297
+
298
+ ### Memory Management
299
+
300
+ ```python
301
+ import asyncio
302
+ import gc
303
+ from boltz2_client import Boltz2Client
304
+
305
+ async def memory_efficient_batch(sequences, batch_size=50):
306
+ client = Boltz2Client("http://localhost:8000")
307
+
308
+ for i in range(0, len(sequences), batch_size):
309
+ batch = sequences[i:i + batch_size]
310
+
311
+ # Process batch
312
+ results = await asyncio.gather(*[
313
+ client.predict_protein_structure(
314
+ sequence=seq,
315
+ recycling_steps=1,
316
+ sampling_steps=20,
317
+ save_structures=False
318
+ )
319
+ for seq in batch
320
+ ])
321
+
322
+ # Process results immediately
323
+ for result in results:
324
+ # Save or process result
325
+ pass
326
+
327
+ # Clean up memory
328
+ del results
329
+ gc.collect()
330
+
331
+ print(f"Completed batch {i//batch_size + 1}")
332
+ ```
333
+
334
+ ## Error Handling
335
+
336
+ ### Comprehensive Error Handling
337
+
338
+ ```python
339
+ import asyncio
340
+ from boltz2_client import Boltz2Client
341
+ from boltz2_client.exceptions import (
342
+ Boltz2APIError,
343
+ Boltz2TimeoutError,
344
+ Boltz2ConnectionError,
345
+ Boltz2ValidationError
346
+ )
347
+
348
+ async def robust_fold(client, sequence, protein_id):
349
+ try:
350
+ response = await client.predict_protein_structure(
351
+ sequence=sequence,
352
+ recycling_steps=1,
353
+ sampling_steps=20,
354
+ save_structures=False
355
+ )
356
+ return {"id": protein_id, "success": True, "result": response}
357
+
358
+ except Boltz2ValidationError as e:
359
+ return {"id": protein_id, "success": False, "error": "validation", "message": str(e)}
360
+ except Boltz2TimeoutError as e:
361
+ return {"id": protein_id, "success": False, "error": "timeout", "message": str(e)}
362
+ except Boltz2ConnectionError as e:
363
+ return {"id": protein_id, "success": False, "error": "connection", "message": str(e)}
364
+ except Boltz2APIError as e:
365
+ return {"id": protein_id, "success": False, "error": "api", "message": str(e)}
366
+ except Exception as e:
367
+ return {"id": protein_id, "success": False, "error": "unknown", "message": str(e)}
368
+ ```
369
+
370
+ ## Best Practices
371
+
372
+ ### 1. Choose Appropriate Concurrency
373
+
374
+ ```python
375
+ # Local endpoint: Limited by GPU memory
376
+ local_concurrent = 3-5
377
+
378
+ # NVIDIA hosted: Limited by rate limits
379
+ hosted_concurrent = 10-20
380
+
381
+ # Start conservative and increase gradually
382
+ ```
383
+
384
+ ### 2. Use Fast Settings for Batch Processing
385
+
386
+ ```python
387
+ # For batch processing, use minimal settings
388
+ batch_settings = {
389
+ "recycling_steps": 1,
390
+ "sampling_steps": 20,
391
+ "save_structures": False
392
+ }
393
+
394
+ # For important predictions, use quality settings
395
+ quality_settings = {
396
+ "recycling_steps": 3,
397
+ "sampling_steps": 50,
398
+ "save_structures": True
399
+ }
400
+ ```
401
+
402
+ ### 3. Implement Proper Error Handling
403
+
404
+ ```python
405
+ # Always handle exceptions gracefully
406
+ # Use retry logic for transient errors
407
+ # Log errors for debugging
408
+ # Continue processing other sequences on individual failures
409
+ ```
410
+
411
+ ### 4. Monitor Resource Usage
412
+
413
+ ```python
414
+ import psutil
415
+ import time
416
+
417
+ async def monitor_resources():
418
+ while True:
419
+ cpu = psutil.cpu_percent()
420
+ memory = psutil.virtual_memory().percent
421
+ print(f"CPU: {cpu}%, Memory: {memory}%")
422
+ await asyncio.sleep(10)
423
+
424
+ # Run monitoring in background
425
+ asyncio.create_task(monitor_resources())
426
+ ```
427
+
428
+ ### 5. Save Results Incrementally
429
+
430
+ ```python
431
+ import json
432
+ from datetime import datetime
433
+
434
+ async def save_results_incrementally(results, filename=None):
435
+ if not filename:
436
+ filename = f"results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
437
+
438
+ with open(filename, 'w') as f:
439
+ json.dump(results, f, indent=2)
440
+
441
+ print(f"Results saved to {filename}")
442
+ ```
443
+
444
+
445
+ ## Troubleshooting
446
+
447
+ ### Common Issues
448
+
449
+ 1. **Too many concurrent requests**: Reduce `max_concurrent`
450
+ 2. **Memory issues**: Use chunked processing
451
+ 3. **Timeout errors**: Increase timeout or reduce complexity
452
+ 4. **Rate limiting**: Add delays between requests
453
+ 5. **Connection errors**: Implement retry logic
454
+
455
+ ### Debugging Tips
456
+
457
+ ```python
458
+ import logging
459
+
460
+ # Enable debug logging
461
+ logging.basicConfig(level=logging.DEBUG)
462
+
463
+ # Add timing information
464
+ import time
465
+ start = time.time()
466
+ # ... your async code ...
467
+ print(f"Total time: {time.time() - start:.2f}s")
468
+ ```
469
+
470
+ This guide provides a comprehensive foundation for async protein folding with the Boltz-2 Python client. Start with the simple examples and gradually implement more advanced patterns as needed.
@@ -0,0 +1,207 @@
1
+ # Covalent Protein-Ligand Complex Prediction Guide
2
+
3
+ Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
4
+
5
+ This guide demonstrates how to test and use the `boltz2-python-client` package for covalent protein-ligand complex prediction.
6
+
7
+ ## ๐Ÿงช Package Status
8
+
9
+ โœ… **WORKING FEATURES:**
10
+ - โœ… Health checks and service monitoring
11
+ - โœ… Basic protein structure prediction (async & sync)
12
+ - โœ… **Covalent protein-ligand complex prediction** ๐ŸŽ‰
13
+ - โœ… Service metadata retrieval
14
+ - โœ… File I/O and result saving (JSON + mmCIF)
15
+ - โœ… CLI interface for basic operations
16
+ - โœ… Type-safe Pydantic models with CCD support
17
+ - โœ… Comprehensive error handling
18
+ - โœ… Progress indicators and rich output
19
+
20
+ โš ๏ธ **COVALENT COMPLEX CONSTRAINTS:**
21
+ - The covalent bond constraint format is working but requires:
22
+ - Correct residue indexing (0-based)
23
+ - Valid cysteine positions in the sequence
24
+ - Proper atom naming conventions
25
+
26
+ ## ๐Ÿš€ Quick Start
27
+
28
+ ### 1. Basic Health Check
29
+ ```bash
30
+ boltz2 health
31
+ ```
32
+
33
+ ### 2. Simple Protein Prediction
34
+ ```bash
35
+ boltz2 protein "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG"
36
+ ```
37
+
38
+ ### 3. **Covalent Complex Prediction** โญ
39
+ ```python
40
+ from boltz2_client import Boltz2Client
41
+ from boltz2_client.models import PredictionRequest, Polymer, Ligand
42
+
43
+ # Updated protein sequence with Cys at position 12
44
+ PROTEIN_SEQUENCE = (
45
+ "MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEY"
46
+ "SAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTK"
47
+ "QAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKE"
48
+ )
49
+
50
+ async def predict_covalent_complex():
51
+ client = Boltz2Client()
52
+
53
+ # Define protein
54
+ protein = Polymer(
55
+ id="A",
56
+ molecule_type="protein",
57
+ sequence=PROTEIN_SEQUENCE
58
+ )
59
+
60
+ # Define U4U ligand using CCD code
61
+ ligand = Ligand(
62
+ id="LIG",
63
+ ccd="U4U" # Chemical Component Dictionary code
64
+ )
65
+
66
+ # Define covalent bond constraint
67
+ bond_constraint = {
68
+ "constraint_type": "bond",
69
+ "atoms": [
70
+ {
71
+ "id": "A",
72
+ "residue_index": 12, # Cys12 (1-based indexing)
73
+ "atom_name": "SG"
74
+ },
75
+ {
76
+ "id": "LIG",
77
+ "residue_index": 1, # First ligand residue
78
+ "atom_name": "C22"
79
+ }
80
+ ]
81
+ }
82
+
83
+ # Create prediction request
84
+ request = PredictionRequest(
85
+ polymers=[protein],
86
+ ligands=[ligand],
87
+ constraints=[bond_constraint],
88
+ recycling_steps=3,
89
+ sampling_steps=50
90
+ )
91
+
92
+ # Run prediction
93
+ response = await client.predict(request, show_progress=True)
94
+
95
+ # Save results
96
+ saved_files = await client.save_prediction(
97
+ response,
98
+ "covalent_results",
99
+ prefix="kras_u4u"
100
+ )
101
+
102
+ return response, saved_files
103
+ ```
104
+
105
+ ## ๐Ÿงฌ **Successful Test Results**
106
+
107
+ ### โœ… **Working Example: KRAS G12C + U4U Covalent Complex**
108
+
109
+ **Test Configuration:**
110
+ - **Protein**: 168 residues with Cys at position 12
111
+ - **Ligand**: U4U (CCD code)
112
+ - **Covalent Bond**: Cys12 SG โ†” LIG C22
113
+ - **Prediction Time**: ~6.4 seconds
114
+ - **Confidence**: 0.904 (excellent!)
115
+
116
+ **Output Files:**
117
+ - `kras_u4u_covalent_20250609_104356.json` - Prediction metadata
118
+ - `kras_u4u_covalent_structure_1_20250609_104356.cif` - mmCIF structure
119
+
120
+ ## ๐Ÿ“‹ **Key Implementation Details**
121
+
122
+ ### 1. **Ligand Specification**
123
+ The package now supports both SMILES and CCD codes:
124
+
125
+ ```python
126
+ # Option 1: CCD code (recommended for known compounds)
127
+ ligand = Ligand(id="LIG", ccd="U4U")
128
+
129
+ # Option 2: SMILES string
130
+ ligand = Ligand(id="LIG", smiles="CC1=C(C=C(C=C1)C(=O)NC2=CC(=C(C=C2)CN3CCN(CC3)C)F)C(F)(F)F")
131
+ ```
132
+
133
+ ### 2. **Constraint Format**
134
+ Covalent bond constraints use this exact format:
135
+
136
+ ```python
137
+ bond_constraint = {
138
+ "constraint_type": "bond",
139
+ "atoms": [
140
+ {
141
+ "id": "A", # Polymer ID
142
+ "residue_index": 12, # 1-based residue number
143
+ "atom_name": "SG" # Atom name (e.g., SG for cysteine sulfur)
144
+ },
145
+ {
146
+ "id": "LIG", # Ligand ID
147
+ "residue_index": 1, # Ligand residue (usually 1)
148
+ "atom_name": "C22" # Ligand atom name
149
+ }
150
+ ]
151
+ }
152
+ ```
153
+
154
+ ### 3. **Indexing Convention**
155
+ - **Residue indexing**: 1-based (Cys12 = residue_index: 12)
156
+ - **Sequence indexing**: 0-based for validation (sequence[11] = 'C')
157
+
158
+ ## ๐Ÿ”ง **Testing Commands**
159
+
160
+ ### Run Example Script
161
+ ```bash
162
+ python examples/04_covalent_bonding.py
163
+ ```
164
+
165
+ ## ๐Ÿ“Š **Expected Results**
166
+
167
+ A successful covalent complex prediction should produce:
168
+
169
+ 1. **High confidence scores** (>0.8 is excellent)
170
+ 2. **mmCIF structure file** with both protein and ligand
171
+ 3. **JSON metadata** with prediction details
172
+ 4. **Reasonable prediction time** (5-15 seconds for this example)
173
+
174
+ ## ๐ŸŽฏ **Best Practices**
175
+
176
+ 1. **Verify cysteine position**: Ensure your sequence has 'C' at the specified position
177
+ 2. **Use CCD codes**: When available, CCD codes are more reliable than SMILES
178
+ 3. **Check confidence**: High confidence (>0.7) indicates reliable predictions
179
+ 4. **Save results**: Always save both JSON metadata and mmCIF structures
180
+ 5. **Monitor progress**: Use `show_progress=True` for long predictions
181
+
182
+ ## ๐Ÿšจ **Common Issues & Solutions**
183
+
184
+ ### Issue: "Field required" error for constraints
185
+ **Solution**: Use the exact constraint format shown above
186
+
187
+ ### Issue: "String should match pattern" for ligand ID
188
+ **Solution**: Use simple IDs like "LIG" instead of complex codes like "U4U"
189
+
190
+ ### Issue: Low confidence at covalent site
191
+ **Solution**: Verify the atom names and residue indices are correct
192
+
193
+ ### Issue: Prediction timeout
194
+ **Solution**: Increase timeout parameter: `client.predict(request, timeout=900)`
195
+
196
+ ## ๐ŸŽ‰ **Success!**
197
+
198
+ The `boltz2-python-client` package is now fully functional for covalent protein-ligand complex prediction!
199
+
200
+ **Key achievements:**
201
+ - โœ… Successful covalent bond constraint implementation
202
+ - โœ… Support for both SMILES and CCD ligand specifications
203
+ - โœ… High-quality predictions with excellent confidence scores
204
+ - โœ… Comprehensive error handling and validation
205
+ - โœ… Professional file output and result management
206
+
207
+ You can now use this package for production covalent complex predictions! ๐Ÿงชโœจ