boltz2-python-client 0.5.2.post1__tar.gz → 0.6.0__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 (149) hide show
  1. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/CHANGELOG.md +21 -3
  2. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/MANIFEST.in +3 -1
  3. boltz2_python_client-0.6.0/PKG-INFO +221 -0
  4. boltz2_python_client-0.6.0/README.md +158 -0
  5. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/__init__.py +1 -1
  6. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/cli/__init__.py +4 -1
  7. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/cli/info.py +6 -16
  8. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/cli/msa.py +6 -3
  9. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/cli/predict.py +21 -14
  10. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/cli/screen.py +4 -1
  11. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/client.py +86 -31
  12. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/models.py +97 -49
  13. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/multi_endpoint_client.py +77 -41
  14. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/utils.py +2 -16
  15. boltz2_python_client-0.6.0/boltz2_python_client.egg-info/PKG-INFO +221 -0
  16. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_python_client.egg-info/SOURCES.txt +35 -33
  17. boltz2_python_client-0.6.0/boltz2_python_client.egg-info/requires.txt +38 -0
  18. boltz2_python_client-0.6.0/docs/a3m_to_multimer_msa.md +39 -0
  19. boltz2_python_client-0.6.0/docs/affinity_prediction.md +59 -0
  20. boltz2_python_client-0.6.0/docs/async.md +37 -0
  21. boltz2_python_client-0.6.0/docs/covalent_complex.md +30 -0
  22. boltz2_python_client-0.6.0/docs/deployment.md +64 -0
  23. boltz2_python_client-0.6.0/docs/development.md +93 -0
  24. boltz2_python_client-0.6.0/docs/migration-0.6.md +62 -0
  25. boltz2_python_client-0.6.0/docs/msa_search.md +46 -0
  26. boltz2_python_client-0.6.0/docs/multi_endpoint.md +38 -0
  27. boltz2_python_client-0.6.0/docs/outputs.md +58 -0
  28. boltz2_python_client-0.6.0/docs/parameters.md +81 -0
  29. boltz2_python_client-0.6.0/docs/refresh-review.md +104 -0
  30. boltz2_python_client-0.6.0/docs/virtual_screening.md +39 -0
  31. boltz2_python_client-0.6.0/docs/yaml.md +52 -0
  32. boltz2_python_client-0.6.0/examples/README.md +51 -0
  33. boltz2_python_client-0.6.0/examples/data/nim_1_9_request.json +8 -0
  34. boltz2_python_client-0.6.0/examples/msa_search.py +13 -0
  35. boltz2_python_client-0.6.0/examples/multi_endpoint.py +15 -0
  36. boltz2_python_client-0.6.0/examples/nim_1_9.py +19 -0
  37. boltz2_python_client-0.6.0/examples/notebooks/01_protein_prediction.ipynb +196 -0
  38. boltz2_python_client-0.6.0/examples/notebooks/02_protein_complexes.ipynb +201 -0
  39. boltz2_python_client-0.6.0/examples/notebooks/03_cdk4_affinity.ipynb +187 -0
  40. boltz2_python_client-0.6.0/examples/notebooks/04_protein_dna_complex.ipynb +135 -0
  41. boltz2_python_client-0.6.0/examples/notebooks/05_covalent_ligand.ipynb +137 -0
  42. boltz2_python_client-0.6.0/examples/paired_msa.py +22 -0
  43. boltz2_python_client-0.6.0/examples/predict.py +8 -0
  44. boltz2_python_client-0.6.0/examples/predict_yaml.py +12 -0
  45. boltz2_python_client-0.6.0/examples/screen.py +18 -0
  46. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/pyproject.toml +14 -5
  47. boltz2_python_client-0.6.0/pytest.ini +35 -0
  48. boltz2_python_client-0.6.0/scripts/start_local_nim.sh +35 -0
  49. boltz2_python_client-0.6.0/scripts/validate_cli.sh +105 -0
  50. boltz2_python_client-0.6.0/scripts/validate_live_nim.py +65 -0
  51. boltz2_python_client-0.6.0/scripts/validate_notebooks.py +76 -0
  52. boltz2_python_client-0.6.0/tests/data/protein_A.a3m +20 -0
  53. boltz2_python_client-0.6.0/tests/data/protein_A_large.a3m +22 -0
  54. boltz2_python_client-0.6.0/tests/data/protein_A_large.fasta +2 -0
  55. boltz2_python_client-0.6.0/tests/data/protein_B.a3m +20 -0
  56. boltz2_python_client-0.6.0/tests/data/protein_B_large.a3m +22 -0
  57. boltz2_python_client-0.6.0/tests/data/protein_B_large.fasta +2 -0
  58. boltz2_python_client-0.6.0/tests/data/sample_protein.a3m +22 -0
  59. boltz2_python_client-0.6.0/tests/fixtures/nim_1_9_request_schema.json +822 -0
  60. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_cli_multi_endpoint.py +45 -53
  61. boltz2_python_client-0.6.0/tests/test_comprehensive_stress.py +134 -0
  62. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_live_endpoints.py +6 -7
  63. boltz2_python_client-0.6.0/tests/test_live_workflows.py +154 -0
  64. boltz2_python_client-0.6.0/tests/test_nim_19.py +243 -0
  65. boltz2_python_client-0.6.0/tests/test_notebooks.py +95 -0
  66. boltz2_python_client-0.5.2.post1/PKG-INFO +0 -324
  67. boltz2_python_client-0.5.2.post1/README.md +0 -278
  68. boltz2_python_client-0.5.2.post1/boltz2_python_client.egg-info/PKG-INFO +0 -324
  69. boltz2_python_client-0.5.2.post1/boltz2_python_client.egg-info/requires.txt +0 -17
  70. boltz2_python_client-0.5.2.post1/docs/a3m_to_multimer_msa.md +0 -599
  71. boltz2_python_client-0.5.2.post1/docs/affinity_prediction.md +0 -292
  72. boltz2_python_client-0.5.2.post1/docs/async.md +0 -510
  73. boltz2_python_client-0.5.2.post1/docs/covalent_complex.md +0 -213
  74. boltz2_python_client-0.5.2.post1/docs/msa_search.md +0 -446
  75. boltz2_python_client-0.5.2.post1/docs/multi_endpoint.md +0 -523
  76. boltz2_python_client-0.5.2.post1/docs/parameters.md +0 -651
  77. boltz2_python_client-0.5.2.post1/docs/virtual_screening.md +0 -327
  78. boltz2_python_client-0.5.2.post1/docs/yaml.md +0 -402
  79. boltz2_python_client-0.5.2.post1/examples/01_basic_protein_folding.py +0 -53
  80. boltz2_python_client-0.5.2.post1/examples/02_protein_structure_prediction_with_msa.py +0 -190
  81. boltz2_python_client-0.5.2.post1/examples/03_protein_ligand_complex.py +0 -237
  82. boltz2_python_client-0.5.2.post1/examples/04_covalent_bonding.py +0 -203
  83. boltz2_python_client-0.5.2.post1/examples/05_dna_protein_complex.py +0 -215
  84. boltz2_python_client-0.5.2.post1/examples/06_yaml_configurations.py +0 -277
  85. boltz2_python_client-0.5.2.post1/examples/07_advanced_parameters.py +0 -347
  86. boltz2_python_client-0.5.2.post1/examples/08_affinity_prediction_simple.py +0 -106
  87. boltz2_python_client-0.5.2.post1/examples/09_virtual_screening.py +0 -226
  88. boltz2_python_client-0.5.2.post1/examples/10_msa_search_integration.py +0 -382
  89. boltz2_python_client-0.5.2.post1/examples/11_msa_search_large_protein.py +0 -394
  90. boltz2_python_client-0.5.2.post1/examples/12_msa_affinity_prediction.py +0 -249
  91. boltz2_python_client-0.5.2.post1/examples/13_a3m_to_multimer_csv.py +0 -371
  92. boltz2_python_client-0.5.2.post1/examples/README.md +0 -102
  93. boltz2_python_client-0.5.2.post1/examples/barnase_barstar_with_msa.py +0 -219
  94. boltz2_python_client-0.5.2.post1/examples/cdk4_msa_affinity_example.py +0 -312
  95. boltz2_python_client-0.5.2.post1/examples/comprehensive_multi_endpoint_demo.py +0 -357
  96. boltz2_python_client-0.5.2.post1/examples/data/cdk2_target.txt +0 -1
  97. boltz2_python_client-0.5.2.post1/examples/data/cdk4_msa_affinity/cdk4_palbociclib_results.json +0 -23
  98. boltz2_python_client-0.5.2.post1/examples/data/kinase_y7w_affinity.json +0 -10
  99. boltz2_python_client-0.5.2.post1/examples/data/msa-kras-g12c_combined.a3m +0 -1178
  100. boltz2_python_client-0.5.2.post1/examples/data/multi_protein_complex.yaml +0 -10
  101. boltz2_python_client-0.5.2.post1/examples/data/sars_cov2_mpro_nirmatrelvir.yaml +0 -8
  102. boltz2_python_client-0.5.2.post1/examples/data/test_msa_endpoint_curl.sh +0 -35
  103. boltz2_python_client-0.5.2.post1/examples/msa_search_simple_demo.py +0 -217
  104. boltz2_python_client-0.5.2.post1/examples/multi_endpoint_screening.py +0 -207
  105. boltz2_python_client-0.5.2.post1/examples/notebooks/01_multimer_prediction.ipynb +0 -687
  106. boltz2_python_client-0.5.2.post1/examples/notebooks/02_cdk4_msa_affinity_prediction.ipynb +0 -1174
  107. boltz2_python_client-0.5.2.post1/examples/notebooks/03_colabfold_a3m_to_multimer.ipynb +0 -658
  108. boltz2_python_client-0.5.2.post1/examples/notebooks/boltz2_comprehensive_demo.ipynb +0 -34
  109. boltz2_python_client-0.5.2.post1/examples/notebooks/boltz2_demo.ipynb +0 -1106
  110. boltz2_python_client-0.5.2.post1/examples/notebooks/boltz2_nim_DNA_Protein_Complex_example_py3Dmol.ipynb +0 -937
  111. boltz2_python_client-0.5.2.post1/examples/notebooks/boltz2_nim_protein_ligand_covalent_complex_molstar_visualization.ipynb +0 -736
  112. boltz2_python_client-0.5.2.post1/tests/test_comprehensive_stress.py +0 -628
  113. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/LICENSE +0 -0
  114. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/__main__.py +0 -0
  115. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/a3m/__init__.py +0 -0
  116. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/a3m/converter.py +0 -0
  117. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/a3m/pairing.py +0 -0
  118. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/a3m/parser.py +0 -0
  119. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/a3m_to_csv_converter.py +0 -0
  120. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/data/__init__.py +0 -0
  121. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/data/speclist.txt +0 -0
  122. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/exceptions.py +0 -0
  123. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/msa_search.py +0 -0
  124. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_client/virtual_screening.py +0 -0
  125. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_python_client.egg-info/dependency_links.txt +0 -0
  126. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_python_client.egg-info/entry_points.txt +0 -0
  127. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/boltz2_python_client.egg-info/top_level.txt +0 -0
  128. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/examples/data/protein_ligand.yaml +0 -0
  129. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/PyYAML-LICENSE +0 -0
  130. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/README.md +0 -0
  131. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/aiofiles-LICENSE +0 -0
  132. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/aiohttp-LICENSE +0 -0
  133. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/click-LICENSE +0 -0
  134. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/httpx-LICENSE +0 -0
  135. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/py3Dmol-LICENSE +0 -0
  136. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/pydantic-LICENSE +0 -0
  137. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/rich-LICENSE +0 -0
  138. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/licenses/typing-extensions-LICENSE +0 -0
  139. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/setup.cfg +0 -0
  140. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/__init__.py +0 -0
  141. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/conftest.py +0 -0
  142. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/constants.py +0 -0
  143. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_a3m_to_csv_converter.py +0 -0
  144. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_basic.py +0 -0
  145. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_examples_syntax.py +0 -0
  146. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_integration_scenarios.py +0 -0
  147. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_msa_search.py +0 -0
  148. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_multi_endpoint_functionality.py +0 -0
  149. {boltz2_python_client-0.5.2.post1 → boltz2_python_client-0.6.0}/tests/test_multi_endpoint_reliability.py +0 -0
@@ -1,3 +1,21 @@
1
+ # 0.6.0 — 2026-09-11
2
+
3
+ - Target NIM 1.9.0: diffusion concurrency and affinity embeddings.
4
+ - Correct PAE/PDE documentation to server-side NPZ artifacts.
5
+ - Reject unknown/malformed request fields; accept protein X residues.
6
+ - Fix YAML affinity conversion and missing-MSA handling.
7
+ - Bound hosted polling, preserve HTTP errors, choose hosted URL automatically.
8
+ - Save complete responses, all scores, and affinity embeddings.
9
+ - Refresh notebooks, deployment instructions, examples and release validation.
10
+ - Consolidate seven notebooks into five numbered workflows, fold A3M pairing
11
+ into protein complexes, and move the SageMaker connection example into docs.
12
+ Show actual NIM/client versions, restore the mature barstar sequence, correct
13
+ DNA strand complementarity, and validate supplied MSA query sequences.
14
+ - Require Python 3.10+; make visualization an optional notebook extra.
15
+ - Forward NIM parameters through async/sync multi-endpoint methods.
16
+ - Return a nonzero CLI status when compound screening fails; report unsupported hosted readiness/metadata calls explicitly.
17
+ - Consolidate duplicate examples and guides; validate actual notebook kernels, viewers, Python methods and Bash CLI workflows.
18
+
1
19
  # Changelog
2
20
 
3
21
  All notable changes to this project will be documented in this file.
@@ -18,9 +36,9 @@ environment should upgrade to `0.5.2.post1`; users who already have
18
36
  followed by `import boltz2_client` raised
19
37
  `ModuleNotFoundError: No module named 'pandas'`. The pandas import is
20
38
  now deferred into the four methods that actually need it
21
- (`CompoundLibrary.from_csv`, `ScreeningResults.to_dataframe`,
22
- `ScreeningResults.get_top_hits`,
23
- `ScreeningResults.get_statistics_by_group`); calling any of those
39
+ (`CompoundLibrary.from_csv`, `VirtualScreeningResult.to_dataframe`,
40
+ `VirtualScreeningResult.get_top_hits`,
41
+ `VirtualScreeningResult.get_statistics_by_group`); calling any of those
24
42
  methods still requires pandas, but importing the package, the CLI,
25
43
  and every other code path no longer does. Callers who use the virtual
26
44
  screening DataFrame helpers should install with
@@ -5,7 +5,9 @@ recursive-include docs *.md
5
5
  recursive-include licenses *.md *.txt LICENSE* *-LICENSE
6
6
  recursive-include boltz2_client *.py
7
7
  recursive-include examples *.py *.yaml *.a3m *.ipynb *.md *.json *.txt *.sh
8
- recursive-include tests *.py
8
+ recursive-include tests *.py *.json *.a3m *.fasta
9
+ recursive-include scripts *.py *.sh
10
+ include pytest.ini
9
11
  recursive-exclude * __pycache__
10
12
  recursive-exclude * *.py[co]
11
13
  recursive-exclude * .DS_Store
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.2
2
+ Name: boltz2-python-client
3
+ Version: 0.6.0
4
+ Summary: Python client for Boltz-2 protein structure prediction API with covalent complex and multi-endpoint support
5
+ Author-email: NVIDIA Corporation <bionemo-support@nvidia.com>
6
+ Maintainer-email: NVIDIA Corporation <bionemo-support@nvidia.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/NVIDIA/digital-biology-examples/tree/main/examples/nims/boltz-2
9
+ Project-URL: Repository, https://github.com/NVIDIA/digital-biology-examples
10
+ Project-URL: Documentation, https://github.com/NVIDIA/digital-biology-examples/tree/main/examples/nims/boltz-2/docs
11
+ Project-URL: Changelog, https://github.com/NVIDIA/digital-biology-examples/blob/main/examples/nims/boltz-2/CHANGELOG.md
12
+ Project-URL: Bug Reports, https://github.com/NVIDIA/digital-biology-examples/issues
13
+ Keywords: protein,structure,prediction,AI,machine learning,bioinformatics,covalent,complex,boltz2
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
25
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Requires-Python: >=3.10
28
+ Description-Content-Type: text/markdown
29
+ License-File: LICENSE
30
+ Requires-Dist: httpx>=0.24.0
31
+ Requires-Dist: pydantic>=2.0.0
32
+ Requires-Dist: typing-extensions>=4.0.0
33
+ Requires-Dist: aiofiles>=23.0.0
34
+ Requires-Dist: rich>=13.0.0
35
+ Requires-Dist: click>=8.0.0
36
+ Requires-Dist: PyYAML>=6.0.0
37
+ Requires-Dist: aiohttp>=3.8.0
38
+ Provides-Extra: screening
39
+ Requires-Dist: pandas>=1.5; extra == "screening"
40
+ Provides-Extra: notebooks
41
+ Requires-Dist: jupyterlab>=4; extra == "notebooks"
42
+ Requires-Dist: ipykernel>=6; extra == "notebooks"
43
+ Requires-Dist: py3Dmol>=2.0; extra == "notebooks"
44
+ Requires-Dist: matplotlib>=3.6; extra == "notebooks"
45
+ Requires-Dist: numpy>=1.23; extra == "notebooks"
46
+ Provides-Extra: analysis
47
+ Requires-Dist: numpy>=1.23; extra == "analysis"
48
+ Requires-Dist: biopython>=1.80; extra == "analysis"
49
+ Provides-Extra: sagemaker
50
+ Requires-Dist: boto3>=1.26.0; extra == "sagemaker"
51
+ Provides-Extra: dev
52
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
53
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
54
+ Requires-Dist: pandas>=1.5.0; extra == "dev"
55
+ Requires-Dist: biopython>=1.80; extra == "dev"
56
+ Requires-Dist: nbformat>=5.7; extra == "dev"
57
+ Requires-Dist: jsonschema>=4.17; extra == "dev"
58
+ Requires-Dist: py3Dmol>=2.0; extra == "dev"
59
+ Requires-Dist: nbclient>=0.7; extra == "dev"
60
+ Requires-Dist: ipykernel>=6; extra == "dev"
61
+ Requires-Dist: build>=1; extra == "dev"
62
+ Requires-Dist: twine>=6; extra == "dev"
63
+
64
+ # Boltz-2 Python Client
65
+
66
+ Copyright (c) 2025-2026, NVIDIA CORPORATION. All rights reserved.
67
+
68
+ [![PyPI](https://img.shields.io/pypi/v/boltz2-python-client)](https://pypi.org/project/boltz2-python-client/)
69
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
70
+
71
+ Python and command-line interfaces for NVIDIA Boltz-2 NIM: protein, DNA/RNA,
72
+ ligand and covalent complexes, binding affinity, MSA integration, templates,
73
+ and multi-endpoint screening.
74
+
75
+ Version **0.6.0** targets **NIM 1.9.0**. Releases are validated on
76
+ [TestPyPI](https://test.pypi.org/project/boltz2-python-client/0.6.0/)
77
+ before production publication. Select the matching index when installing.
78
+ See [migration and compatibility](docs/migration-0.6.md).
79
+
80
+ The source archive (`.tar.gz`) under the release page's **Download files** includes
81
+ the current guides, scripts and notebooks. Relative links in this README refer
82
+ to files in that extracted archive or a matching repository checkout.
83
+
84
+ ## Install
85
+
86
+ Python 3.10 or newer:
87
+
88
+ ```bash
89
+ # PyPI, after production publication
90
+ python -m pip install boltz2-python-client==0.6.0
91
+
92
+ # TestPyPI release and dependencies from PyPI
93
+ python -m pip install --index-url https://test.pypi.org/simple/ \
94
+ --extra-index-url https://pypi.org/simple/ boltz2-python-client==0.6.0
95
+
96
+ # From this checkout or the extracted source archive
97
+ python -m pip install -e '.[dev,notebooks]'
98
+ ```
99
+
100
+ Optional extras: `notebooks` (Jupyter and visualization), `sagemaker` (boto3),
101
+ `analysis` (NumPy and structure conversion), and `screening` (pandas for CSV and
102
+ DataFrame helpers). The Python client itself needs no GPU;
103
+ a running NIM server performs inference.
104
+
105
+ ## Quick start
106
+
107
+ Run against a ready local server. This sequence is an input-format example;
108
+ confidence scores do not establish a biological interaction.
109
+
110
+ ```python
111
+ from pathlib import Path
112
+ from boltz2_client import Boltz2SyncClient
113
+
114
+ client = Boltz2SyncClient(base_url="http://localhost:8000", timeout=600)
115
+ result = client.predict_protein_structure(
116
+ sequence="MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG",
117
+ output_dir=Path("results/protein"),
118
+ )
119
+ print(result.confidence_scores)
120
+ ```
121
+
122
+ For notebooks and asynchronous programs, use `Boltz2Client` and `await`:
123
+
124
+ ```python
125
+ from boltz2_client import Boltz2Client, Ligand, Polymer, PredictionRequest
126
+
127
+ client = Boltz2Client(timeout=600)
128
+ request = PredictionRequest(
129
+ polymers=[Polymer(id="A", molecule_type="protein", sequence="MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPT")],
130
+ ligands=[Ligand(id="L1", smiles="CC(=O)Oc1ccccc1C(=O)O",
131
+ predict_affinity=True, output_affinity_embedding=True)],
132
+ diffusion_samples=2,
133
+ max_parallel_samples=1, # NIM 1.9+: lower peak GPU memory
134
+ )
135
+ result = await client.predict(request, output_dir="results/complex")
136
+ print(result.affinities["L1"].affinity_pic50)
137
+ print(result.affinities["L1"].affinity_embedding)
138
+ ```
139
+
140
+ The second example demonstrates request syntax using a short protein fragment
141
+ and aspirin; it is not a validated binding pair. Use full, appropriate target
142
+ sequences and assess predictions against experimental evidence.
143
+
144
+ ## Endpoints
145
+
146
+ | Deployment | Configuration | Prediction path |
147
+ |---|---|---|
148
+ | Local/self-hosted | `Boltz2Client(base_url="http://localhost:8000")` | `/biology/mit/boltz2/predict` |
149
+ | NVIDIA hosted | `Boltz2Client(endpoint_type="nvidia_hosted")` | `/v1/biology/mit/boltz2/predict` |
150
+ | SageMaker | `Boltz2Client(endpoint_type="sagemaker", sagemaker_endpoint_name="my-endpoint")` | boto3 `invoke_endpoint` |
151
+
152
+ For hosted inference, supply the key through `NVIDIA_API_KEY` or `NGC_API_KEY`
153
+ in the process environment (or `api_key` in Python). The default hosted base
154
+ URL is `https://health.api.nvidia.com`. Local inference sends no authorization
155
+ header. Hosted deployments may lag the container release; enable version-specific
156
+ options only when that endpoint supports them.
157
+
158
+ SageMaker requires the `sagemaker` extra and configured AWS credentials/region.
159
+ See the [SageMaker connection example](docs/deployment.md#existing-sagemaker-endpoint).
160
+ Use asynchronous clients in Jupyter; the synchronous wrapper uses `asyncio.run()`.
161
+
162
+ ## CLI
163
+
164
+ ```bash
165
+ boltz2 health
166
+ boltz2 protein ACDEFGHIKLMNPQRSTVWY --output-dir results/protein
167
+ boltz2 protein ACDEFGHIKLMNPQRSTVWY --diffusion-samples 2 --max-parallel-samples 1
168
+ boltz2 ligand ACDEFGHIKLMNPQRSTVWY --smiles CC --predict-affinity --output-affinity-embedding
169
+ boltz2 advanced --config-file examples/data/nim_1_9_request.json --output-dir results/advanced
170
+ boltz2 --endpoint-type nvidia_hosted protein ACDEFGHIKLMNPQRSTVWY
171
+ boltz2 --multi-endpoint --base-url http://gpu1:8000,http://gpu2:8000 protein ACDEFGHIKLMNPQRSTVWY
172
+ ```
173
+
174
+ These short sequences/ligands illustrate syntax. `boltz2 --help` lists all
175
+ commands, including covalent constraints, YAML, MSA conversion and screening.
176
+
177
+ ## Results and matrices
178
+
179
+ `predict()` saves every structure as `structure_0.cif`, `structure_1.cif`, etc.,
180
+ plus `prediction_response.json` (complete response), `prediction_metadata.json`
181
+ (scores, affinities, embeddings and runtime metrics), and `affinities.json` when
182
+ present. Use `save_structures=False` or CLI `--no-save` to suppress client output.
183
+ Use separate output directories for separate predictions to avoid overwriting files.
184
+
185
+ **NIM 1.9 does not return full PAE/PDE matrices in JSON.** `write_full_pae=True`
186
+ and `write_full_pde=True` create NPZ files on the server under
187
+ `$NIM_OUTPUT_PATH/prediction_*/pae/` and `.../pde/`. `result.pae` and `result.pde`
188
+ remain `None`. Mount the server output directory to retrieve these artifacts.
189
+ Aggregate `complex_pde_scores` and `complex_ipde_scores` remain in the response.
190
+ See [outputs](docs/outputs.md) for loading matrices and retaining results.
191
+
192
+ ## Deploy a local server
193
+
194
+ Follow [local deployment](docs/deployment.md), including GPU/driver prerequisites,
195
+ NGC login, cache and output mounts. The pinned image is
196
+ `nvcr.io/nim/mit/boltz2:1.9.0`. The deployment script checks GPU access before
197
+ starting a container:
198
+
199
+ ```bash
200
+ # Set NGC_API_KEY (or NVIDIA_API_KEY) in the environment first.
201
+ export LOCAL_NIM_CACHE="$HOME/.cache/nim"
202
+ export LOCAL_NIM_OUTPUT="$HOME/boltz2-output"
203
+ bash scripts/start_local_nim.sh
204
+ ```
205
+
206
+ ## Guides and examples
207
+
208
+ Start with the [protein prediction notebook](examples/notebooks/01_protein_prediction.ipynb)
209
+ and [example index](examples/README.md). Guides:
210
+
211
+ - [Parameters](docs/parameters.md), [migration](docs/migration-0.6.md), [outputs](docs/outputs.md)
212
+ - [Affinity](docs/affinity_prediction.md), [covalent complexes](docs/covalent_complex.md)
213
+ - [MSA search](docs/msa_search.md), [A3M multimer pairing](docs/a3m_to_multimer_msa.md)
214
+ - [YAML subset](docs/yaml.md), [async usage](docs/async.md)
215
+ - [Multiple endpoints](docs/multi_endpoint.md), [virtual screening](docs/virtual_screening.md)
216
+ - [Validation and release procedure](docs/development.md), [changelog](CHANGELOG.md)
217
+
218
+ ## License
219
+
220
+ [MIT](LICENSE). Third-party assets retain their [licenses](licenses/README.md).
221
+ NVIDIA NIM container and model terms are separate from the Python client license.
@@ -0,0 +1,158 @@
1
+ # Boltz-2 Python Client
2
+
3
+ Copyright (c) 2025-2026, NVIDIA CORPORATION. All rights reserved.
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/boltz2-python-client)](https://pypi.org/project/boltz2-python-client/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+
8
+ Python and command-line interfaces for NVIDIA Boltz-2 NIM: protein, DNA/RNA,
9
+ ligand and covalent complexes, binding affinity, MSA integration, templates,
10
+ and multi-endpoint screening.
11
+
12
+ Version **0.6.0** targets **NIM 1.9.0**. Releases are validated on
13
+ [TestPyPI](https://test.pypi.org/project/boltz2-python-client/0.6.0/)
14
+ before production publication. Select the matching index when installing.
15
+ See [migration and compatibility](docs/migration-0.6.md).
16
+
17
+ The source archive (`.tar.gz`) under the release page's **Download files** includes
18
+ the current guides, scripts and notebooks. Relative links in this README refer
19
+ to files in that extracted archive or a matching repository checkout.
20
+
21
+ ## Install
22
+
23
+ Python 3.10 or newer:
24
+
25
+ ```bash
26
+ # PyPI, after production publication
27
+ python -m pip install boltz2-python-client==0.6.0
28
+
29
+ # TestPyPI release and dependencies from PyPI
30
+ python -m pip install --index-url https://test.pypi.org/simple/ \
31
+ --extra-index-url https://pypi.org/simple/ boltz2-python-client==0.6.0
32
+
33
+ # From this checkout or the extracted source archive
34
+ python -m pip install -e '.[dev,notebooks]'
35
+ ```
36
+
37
+ Optional extras: `notebooks` (Jupyter and visualization), `sagemaker` (boto3),
38
+ `analysis` (NumPy and structure conversion), and `screening` (pandas for CSV and
39
+ DataFrame helpers). The Python client itself needs no GPU;
40
+ a running NIM server performs inference.
41
+
42
+ ## Quick start
43
+
44
+ Run against a ready local server. This sequence is an input-format example;
45
+ confidence scores do not establish a biological interaction.
46
+
47
+ ```python
48
+ from pathlib import Path
49
+ from boltz2_client import Boltz2SyncClient
50
+
51
+ client = Boltz2SyncClient(base_url="http://localhost:8000", timeout=600)
52
+ result = client.predict_protein_structure(
53
+ sequence="MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG",
54
+ output_dir=Path("results/protein"),
55
+ )
56
+ print(result.confidence_scores)
57
+ ```
58
+
59
+ For notebooks and asynchronous programs, use `Boltz2Client` and `await`:
60
+
61
+ ```python
62
+ from boltz2_client import Boltz2Client, Ligand, Polymer, PredictionRequest
63
+
64
+ client = Boltz2Client(timeout=600)
65
+ request = PredictionRequest(
66
+ polymers=[Polymer(id="A", molecule_type="protein", sequence="MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPT")],
67
+ ligands=[Ligand(id="L1", smiles="CC(=O)Oc1ccccc1C(=O)O",
68
+ predict_affinity=True, output_affinity_embedding=True)],
69
+ diffusion_samples=2,
70
+ max_parallel_samples=1, # NIM 1.9+: lower peak GPU memory
71
+ )
72
+ result = await client.predict(request, output_dir="results/complex")
73
+ print(result.affinities["L1"].affinity_pic50)
74
+ print(result.affinities["L1"].affinity_embedding)
75
+ ```
76
+
77
+ The second example demonstrates request syntax using a short protein fragment
78
+ and aspirin; it is not a validated binding pair. Use full, appropriate target
79
+ sequences and assess predictions against experimental evidence.
80
+
81
+ ## Endpoints
82
+
83
+ | Deployment | Configuration | Prediction path |
84
+ |---|---|---|
85
+ | Local/self-hosted | `Boltz2Client(base_url="http://localhost:8000")` | `/biology/mit/boltz2/predict` |
86
+ | NVIDIA hosted | `Boltz2Client(endpoint_type="nvidia_hosted")` | `/v1/biology/mit/boltz2/predict` |
87
+ | SageMaker | `Boltz2Client(endpoint_type="sagemaker", sagemaker_endpoint_name="my-endpoint")` | boto3 `invoke_endpoint` |
88
+
89
+ For hosted inference, supply the key through `NVIDIA_API_KEY` or `NGC_API_KEY`
90
+ in the process environment (or `api_key` in Python). The default hosted base
91
+ URL is `https://health.api.nvidia.com`. Local inference sends no authorization
92
+ header. Hosted deployments may lag the container release; enable version-specific
93
+ options only when that endpoint supports them.
94
+
95
+ SageMaker requires the `sagemaker` extra and configured AWS credentials/region.
96
+ See the [SageMaker connection example](docs/deployment.md#existing-sagemaker-endpoint).
97
+ Use asynchronous clients in Jupyter; the synchronous wrapper uses `asyncio.run()`.
98
+
99
+ ## CLI
100
+
101
+ ```bash
102
+ boltz2 health
103
+ boltz2 protein ACDEFGHIKLMNPQRSTVWY --output-dir results/protein
104
+ boltz2 protein ACDEFGHIKLMNPQRSTVWY --diffusion-samples 2 --max-parallel-samples 1
105
+ boltz2 ligand ACDEFGHIKLMNPQRSTVWY --smiles CC --predict-affinity --output-affinity-embedding
106
+ boltz2 advanced --config-file examples/data/nim_1_9_request.json --output-dir results/advanced
107
+ boltz2 --endpoint-type nvidia_hosted protein ACDEFGHIKLMNPQRSTVWY
108
+ boltz2 --multi-endpoint --base-url http://gpu1:8000,http://gpu2:8000 protein ACDEFGHIKLMNPQRSTVWY
109
+ ```
110
+
111
+ These short sequences/ligands illustrate syntax. `boltz2 --help` lists all
112
+ commands, including covalent constraints, YAML, MSA conversion and screening.
113
+
114
+ ## Results and matrices
115
+
116
+ `predict()` saves every structure as `structure_0.cif`, `structure_1.cif`, etc.,
117
+ plus `prediction_response.json` (complete response), `prediction_metadata.json`
118
+ (scores, affinities, embeddings and runtime metrics), and `affinities.json` when
119
+ present. Use `save_structures=False` or CLI `--no-save` to suppress client output.
120
+ Use separate output directories for separate predictions to avoid overwriting files.
121
+
122
+ **NIM 1.9 does not return full PAE/PDE matrices in JSON.** `write_full_pae=True`
123
+ and `write_full_pde=True` create NPZ files on the server under
124
+ `$NIM_OUTPUT_PATH/prediction_*/pae/` and `.../pde/`. `result.pae` and `result.pde`
125
+ remain `None`. Mount the server output directory to retrieve these artifacts.
126
+ Aggregate `complex_pde_scores` and `complex_ipde_scores` remain in the response.
127
+ See [outputs](docs/outputs.md) for loading matrices and retaining results.
128
+
129
+ ## Deploy a local server
130
+
131
+ Follow [local deployment](docs/deployment.md), including GPU/driver prerequisites,
132
+ NGC login, cache and output mounts. The pinned image is
133
+ `nvcr.io/nim/mit/boltz2:1.9.0`. The deployment script checks GPU access before
134
+ starting a container:
135
+
136
+ ```bash
137
+ # Set NGC_API_KEY (or NVIDIA_API_KEY) in the environment first.
138
+ export LOCAL_NIM_CACHE="$HOME/.cache/nim"
139
+ export LOCAL_NIM_OUTPUT="$HOME/boltz2-output"
140
+ bash scripts/start_local_nim.sh
141
+ ```
142
+
143
+ ## Guides and examples
144
+
145
+ Start with the [protein prediction notebook](examples/notebooks/01_protein_prediction.ipynb)
146
+ and [example index](examples/README.md). Guides:
147
+
148
+ - [Parameters](docs/parameters.md), [migration](docs/migration-0.6.md), [outputs](docs/outputs.md)
149
+ - [Affinity](docs/affinity_prediction.md), [covalent complexes](docs/covalent_complex.md)
150
+ - [MSA search](docs/msa_search.md), [A3M multimer pairing](docs/a3m_to_multimer_msa.md)
151
+ - [YAML subset](docs/yaml.md), [async usage](docs/async.md)
152
+ - [Multiple endpoints](docs/multi_endpoint.md), [virtual screening](docs/virtual_screening.md)
153
+ - [Validation and release procedure](docs/development.md), [changelog](CHANGELOG.md)
154
+
155
+ ## License
156
+
157
+ [MIT](LICENSE). Third-party assets retain their [licenses](licenses/README.md).
158
+ NVIDIA NIM container and model terms are separate from the Python client license.
@@ -26,7 +26,7 @@ Example:
26
26
  >>> print(f"Confidence: {result.confidence_scores[0]:.3f}")
27
27
  """
28
28
 
29
- __version__ = "0.5.2.post1"
29
+ __version__ = "0.6.0"
30
30
  __author__ = "NVIDIA Corporation"
31
31
  __email__ = "bionemo-support@nvidia.com"
32
32
 
@@ -56,7 +56,7 @@ def print_warning(message: str):
56
56
  @click.group()
57
57
  @click.version_option(_pkg_version, "-V", "--version", prog_name="boltz2",
58
58
  message="%(prog)s %(version)s")
59
- @click.option('--base-url', default='http://localhost:8000', help='Service base URL (can be comma-separated for multiple endpoints)')
59
+ @click.option('--base-url', default=None, help='Service base URL (can be comma-separated for multiple endpoints)')
60
60
  @click.option('--api-key', help='API key for NVIDIA hosted endpoints (or set NVIDIA_API_KEY env var)')
61
61
  @click.option('--endpoint-type',
62
62
  type=click.Choice(['local', 'nvidia_hosted', 'sagemaker']),
@@ -109,6 +109,9 @@ def cli(ctx, base_url: str, api_key: Optional[str], endpoint_type: str,
109
109
  export SAGEMAKER_ENDPOINT_NAME=my-boltz2-endpoint
110
110
  boltz2 --endpoint-type sagemaker protein "MKTVRQERLK..."
111
111
  """
112
+ if base_url is not None and not base_url.strip():
113
+ raise click.BadParameter("must not be empty", param_hint="--base-url")
114
+ base_url = base_url or ("https://health.api.nvidia.com" if endpoint_type == "nvidia_hosted" else "http://localhost:8000")
112
115
  ctx.ensure_object(dict)
113
116
  ctx.obj['base_url'] = base_url
114
117
  ctx.obj['api_key'] = api_key
@@ -28,18 +28,7 @@ def health(ctx):
28
28
  try:
29
29
  # Handle NVIDIA hosted endpoints specially
30
30
  if ctx.obj['endpoint_type'] == 'nvidia_hosted':
31
- print_warning("Health checks are not supported on NVIDIA hosted endpoints")
32
- print_info("NVIDIA hosted endpoints use managed infrastructure with built-in health monitoring")
33
- print_success("NVIDIA endpoint is considered healthy if you can make predictions")
34
-
35
- if ctx.obj['verbose']:
36
- console.print("\nService Info:", style="bold")
37
- console.print(f" Base URL: {ctx.obj['base_url']}")
38
- console.print(f" Endpoint Type: {ctx.obj['endpoint_type']}")
39
- console.print(f" API Key: {'✅ Set via environment' if ctx.obj.get('api_key') is None else '✅ Provided via CLI'}")
40
- console.print(f" Note: To verify connectivity, try running a prediction command")
41
-
42
- print_info("To test connectivity, try: boltz2 --endpoint-type nvidia_hosted protein \"SEQUENCE\" --no-save")
31
+ raise click.ClickException("NVIDIA hosted inference has no readiness API; verify availability with a prediction.")
43
32
  else:
44
33
  # Local endpoint - use normal health check
45
34
  client = create_client(ctx)
@@ -64,11 +53,12 @@ def health(ctx):
64
53
  for key, value in health_status.details.items():
65
54
  console.print(f" {key}: {value}")
66
55
 
56
+ except click.ClickException:
57
+ raise
67
58
  except Exception as e:
68
- if ctx.obj['endpoint_type'] not in ('nvidia_hosted',):
69
- print_error(f"Health check failed: {e}")
70
- raise click.Abort()
71
-
59
+ print_error(f"Health check failed: {e}")
60
+ raise click.Abort()
61
+
72
62
  asyncio.run(check_health())
73
63
 
74
64
 
@@ -559,9 +559,9 @@ def convert_msa_command(ctx, a3m_files: Tuple[str, ...], chain_ids: str,
559
559
  @click.option('--diffusion-samples', type=click.IntRange(1, 25), default=1,
560
560
  help='Number of diffusion samples/structures (1-25, default: 1)')
561
561
  @click.option('--write-full-pae', is_flag=True, default=False,
562
- help='Output full PAE (Predicted Aligned Error) matrix')
562
+ help='Write PAE NPZ files on the NIM 1.9+ server')
563
563
  @click.option('--write-full-pde', is_flag=True, default=False,
564
- help='Output full PDE (Predicted Distance Error) matrix')
564
+ help='Write PDE NPZ files on the NIM 1.9+ server')
565
565
  @click.option('--output-format', type=click.Choice(['cif', 'pdb']), default='cif',
566
566
  help='Output structure format: cif (default) or pdb')
567
567
  @click.pass_context
@@ -825,7 +825,10 @@ def multimer_msa_command(ctx, a3m_files: Tuple[str, ...], chain_ids: str,
825
825
  if response.ptm_scores:
826
826
  print_info(f"pTM: {response.ptm_scores[0]:.4f}")
827
827
 
828
- # Save PAE matrix if available
828
+ if write_full_pae or write_full_pde:
829
+ print_info("NIM 1.9+ matrix files are under server NIM_OUTPUT_PATH; JSON pae/pde fields are null.")
830
+
831
+ # Save legacy inline PAE matrix if available
829
832
  if write_full_pae and response.pae:
830
833
  pae_path = output_path.with_suffix('.pae.json')
831
834
  pae_path.write_text(json.dumps({'pae': response.pae}, indent=2))
@@ -38,6 +38,7 @@ def create_client(ctx):
38
38
  help='Number of sampling steps (10-1000, default: 50)')
39
39
  @click.option('--diffusion-samples', default=1, type=click.IntRange(1, 25),
40
40
  help='Number of diffusion samples (1-25, default: 1)')
41
+ @click.option('--max-parallel-samples', default=None, type=click.IntRange(1, 25), help='Concurrent diffusion samples (NIM 1.9+)')
41
42
  @click.option('--step-scale', default=1.638, type=click.FloatRange(0.5, 5.0),
42
43
  help='Step scale for diffusion sampling (0.5-5.0, default: 1.638)')
43
44
  @click.option('--msa-file', multiple=True, type=(str, click.Choice(['a3m', 'csv', 'fasta'])),
@@ -45,16 +46,16 @@ def create_client(ctx):
45
46
  @click.option('--output-dir', type=click.Path(), default='.', help='Directory to save output files (structure_0.cif, prediction_metadata.json). Default: current directory')
46
47
  @click.option('--no-save', is_flag=True, help='Do not save structure files')
47
48
  @click.option('--write-full-pae', is_flag=True, default=False,
48
- help='Output full PAE (Predicted Aligned Error) matrix as JSON')
49
+ help='Write PAE NPZ files under NIM_OUTPUT_PATH on the NIM 1.9+ server')
49
50
  @click.option('--write-full-pde', is_flag=True, default=False,
50
- help='Output full PDE (Predicted Distance Error) matrix as JSON')
51
+ help='Write PDE NPZ files under NIM_OUTPUT_PATH on the NIM 1.9+ server')
51
52
  @click.option('--output-format', type=click.Choice(['cif', 'pdb']), default='cif',
52
53
  help='Output structure format: cif (default) or pdb')
53
54
  @click.pass_context
54
55
  def protein(ctx, sequence: str, polymer_id: str, recycling_steps: int, sampling_steps: int,
55
56
  diffusion_samples: int, step_scale: float, msa_file: List[Tuple[str, str]],
56
57
  output_dir: str, no_save: bool, write_full_pae: bool, write_full_pde: bool,
57
- output_format: str):
58
+ output_format: str, max_parallel_samples: Optional[int]):
58
59
  """
59
60
  Predict protein structure with optional MSA guidance.
60
61
 
@@ -118,6 +119,7 @@ def protein(ctx, sequence: str, polymer_id: str, recycling_steps: int, sampling_
118
119
  recycling_steps=recycling_steps,
119
120
  sampling_steps=sampling_steps,
120
121
  diffusion_samples=diffusion_samples,
122
+ max_parallel_samples=max_parallel_samples,
121
123
  step_scale=step_scale,
122
124
  write_full_pae=write_full_pae,
123
125
  write_full_pde=write_full_pde
@@ -164,8 +166,11 @@ def protein(ctx, sequence: str, polymer_id: str, recycling_steps: int, sampling_
164
166
  convert_cif_to_pdb(cif_path, pdb_path)
165
167
  print_info(f"Converted to PDB: {pdb_path}")
166
168
 
167
- # Save PAE matrix if requested and available
168
- if write_full_pae and result.pae:
169
+ if write_full_pae or write_full_pde:
170
+ print_info("NIM 1.9+ writes matrices under server NIM_OUTPUT_PATH/prediction_*/{pae,pde}/. The JSON pae/pde fields are null; mount the server output directory to access NPZ files.")
171
+
172
+ # Save legacy inline matrices if available
173
+ if not no_save and write_full_pae and result.pae:
169
174
  import json
170
175
  pae_path = Path(output_dir) / f"structure_{polymer_id}.pae.json"
171
176
  pae_path.write_text(json.dumps({'pae': result.pae}, indent=2))
@@ -173,7 +178,7 @@ def protein(ctx, sequence: str, polymer_id: str, recycling_steps: int, sampling_
173
178
  print_info(f"PAE matrix saved to: {pae_path} (shape: {pae_shape})")
174
179
 
175
180
  # Save PDE matrix if requested and available
176
- if write_full_pde and result.pde:
181
+ if not no_save and write_full_pde and result.pde:
177
182
  import json
178
183
  pde_path = Path(output_dir) / f"structure_{polymer_id}.pde.json"
179
184
  pde_path.write_text(json.dumps({'pde': result.pde}, indent=2))
@@ -197,6 +202,7 @@ def protein(ctx, sequence: str, polymer_id: str, recycling_steps: int, sampling_
197
202
  @click.option('--recycling-steps', default=3, type=click.IntRange(1, 10))
198
203
  @click.option('--sampling-steps', default=50, type=click.IntRange(10, 1000))
199
204
  @click.option('--predict-affinity', is_flag=True, help='Enable affinity prediction for the ligand')
205
+ @click.option('--output-affinity-embedding', is_flag=True, help='Return affinity embeddings; requires --predict-affinity (NIM 1.8+)')
200
206
  @click.option('--sampling-steps-affinity', default=200, type=click.IntRange(10, 1000), help='Sampling steps for affinity prediction (default: 200)')
201
207
  @click.option('--diffusion-samples-affinity', default=5, type=click.IntRange(1, 10), help='Diffusion samples for affinity prediction (default: 5)')
202
208
  @click.option('--affinity-mw-correction', is_flag=True, help='Apply molecular weight correction to affinity prediction')
@@ -210,7 +216,7 @@ def ligand(ctx, protein_sequence: str, smiles: Optional[str], ccd: Optional[str]
210
216
  recycling_steps: int, sampling_steps: int, predict_affinity: bool,
211
217
  sampling_steps_affinity: int, diffusion_samples_affinity: int,
212
218
  affinity_mw_correction: bool, msa_file: List[Tuple[str, str]],
213
- output_dir: str, no_save: bool):
219
+ output_dir: str, no_save: bool, output_affinity_embedding: bool):
214
220
  """
215
221
  Predict protein-ligand complex structure with optional MSA guidance.
216
222
 
@@ -284,10 +290,11 @@ def ligand(ctx, protein_sequence: str, smiles: Optional[str], ccd: Optional[str]
284
290
  recycling_steps=recycling_steps,
285
291
  sampling_steps=sampling_steps,
286
292
  predict_affinity=predict_affinity,
293
+ output_affinity_embedding=output_affinity_embedding,
287
294
  sampling_steps_affinity=sampling_steps_affinity,
288
295
  diffusion_samples_affinity=diffusion_samples_affinity,
289
296
  affinity_mw_correction=affinity_mw_correction,
290
- save_structures=False,
297
+ save_structures=not no_save,
291
298
  msa_files=msa_files if msa_files else None,
292
299
  output_dir=Path(output_dir),
293
300
  progress_callback=progress_callback
@@ -323,16 +330,16 @@ def ligand(ctx, protein_sequence: str, smiles: Optional[str], ccd: Optional[str]
323
330
 
324
331
  # Interpretation
325
332
  if affinity.affinity_probability_binary[0] > 0.7:
326
- print_success("Strong binding predicted (>70% probability)")
333
+ print_success("High predicted binder likelihood (>70% probability)")
327
334
  elif affinity.affinity_probability_binary[0] > 0.5:
328
- print_info("Moderate binding predicted (>50% probability)")
335
+ print_info("Predicted binder likelihood above 50%")
329
336
  else:
330
- print_info("Weak binding predicted (<50% probability)")
337
+ print_info("Predicted binder likelihood at or below 50%")
331
338
 
332
339
  # Save results
333
340
  if not no_save:
334
341
  output_path = Path(output_dir)
335
- output_path.mkdir(exist_ok=True)
342
+ output_path.mkdir(parents=True, exist_ok=True)
336
343
 
337
344
  # Save structure
338
345
  structure_file = output_path / "structure_0.cif"
@@ -732,7 +739,7 @@ def yaml_config(ctx, yaml_file: str, msa_dir: Optional[str], recycling_steps: in
732
739
  """
733
740
  Run prediction from YAML configuration file (official Boltz format).
734
741
 
735
- This command supports the official Boltz YAML configuration format as used
742
+ This command supports the supported Boltz YAML configuration subset as used
736
743
  in the original Boltz repository examples.
737
744
 
738
745
  YAML_FILE: Path to YAML configuration file
@@ -845,7 +852,7 @@ def yaml_config(ctx, yaml_file: str, msa_dir: Optional[str], recycling_steps: in
845
852
  if polymer_idx < len(request.polymers):
846
853
  request.polymers[polymer_idx].msa = {"default": {format_type: msa_record}}
847
854
  else:
848
- print_warning(f"MSA file not found: {msa_path}")
855
+ raise ValueError(f"MSA file not found: {msa_path}")
849
856
 
850
857
  # Override with CLI parameters
851
858
  request.recycling_steps = recycling_steps