mutadock 2.2.0__tar.gz → 2.2.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 (95) hide show
  1. {mutadock-2.2.0 → mutadock-2.2.2}/.gitignore +4 -4
  2. {mutadock-2.2.0 → mutadock-2.2.2}/CHANGELOG.md +15 -0
  3. {mutadock-2.2.0 → mutadock-2.2.2}/PKG-INFO +51 -19
  4. {mutadock-2.2.0 → mutadock-2.2.2}/README.md +49 -18
  5. {mutadock-2.2.0 → mutadock-2.2.2}/docs/conf.py +2 -2
  6. {mutadock-2.2.0 → mutadock-2.2.2}/docs/index.rst +88 -35
  7. {mutadock-2.2.0 → mutadock-2.2.2}/environment.yml +3 -2
  8. {mutadock-2.2.0 → mutadock-2.2.2}/install.sh +3 -1
  9. {mutadock-2.2.0 → mutadock-2.2.2}/pyproject.toml +5 -4
  10. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/__init__.py +1 -1
  11. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/docking/vina_helper.py +34 -22
  12. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/csv_generator.py +2 -2
  13. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_docking/test_vina_helper.py +37 -5
  14. {mutadock-2.2.0 → mutadock-2.2.2}/win_install.bat +3 -1
  15. {mutadock-2.2.0 → mutadock-2.2.2}/.dockerignore +0 -0
  16. {mutadock-2.2.0 → mutadock-2.2.2}/.pre-commit-config.yaml +0 -0
  17. {mutadock-2.2.0 → mutadock-2.2.2}/.readthedocs.yaml +0 -0
  18. {mutadock-2.2.0 → mutadock-2.2.2}/Dockerfile +0 -0
  19. {mutadock-2.2.0 → mutadock-2.2.2}/LICENSE +0 -0
  20. {mutadock-2.2.0 → mutadock-2.2.2}/data/4QJR.cif +0 -0
  21. {mutadock-2.2.0 → mutadock-2.2.2}/data/BLOSUM62 +0 -0
  22. {mutadock-2.2.0 → mutadock-2.2.2}/data/Ligand.sdf +0 -0
  23. {mutadock-2.2.0 → mutadock-2.2.2}/data/PAM250 +0 -0
  24. {mutadock-2.2.0 → mutadock-2.2.2}/docs/Makefile +0 -0
  25. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/index.rst +0 -0
  26. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.docking.exceptions.rst +0 -0
  27. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.docking.np_docking.rst +0 -0
  28. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.docking.vina_dock.rst +0 -0
  29. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.docking.vina_helper.rst +0 -0
  30. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.Amino.rst +0 -0
  31. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.csv_generator.rst +0 -0
  32. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.csv_sort.rst +0 -0
  33. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.ddg_calc.rst +0 -0
  34. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.ddg_calc_double.rst +0 -0
  35. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.ddg_calc_triple.rst +0 -0
  36. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.exceptions.rst +0 -0
  37. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.generate_mutant_pdb.rst +0 -0
  38. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.generate_mutants.rst +0 -0
  39. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.helpers.rst +0 -0
  40. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.np_mutation.rst +0 -0
  41. {mutadock-2.2.0 → mutadock-2.2.2}/docs/api/mutadock.mutation.predict_ddG.rst +0 -0
  42. {mutadock-2.2.0 → mutadock-2.2.2}/docs/make.bat +0 -0
  43. {mutadock-2.2.0 → mutadock-2.2.2}/pyrightconfig.json +0 -0
  44. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/data/BLOSUM62 +0 -0
  45. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/data/PAM250 +0 -0
  46. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/docking/__init__.py +0 -0
  47. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/docking/exceptions.py +0 -0
  48. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/docking/np_docking.py +0 -0
  49. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/docking/vina_dock.py +0 -0
  50. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/Amino.py +0 -0
  51. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/__init__.py +0 -0
  52. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/csv_sort.py +0 -0
  53. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/ddg_calc.py +0 -0
  54. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/ddg_calc_double.py +0 -0
  55. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/ddg_calc_triple.py +0 -0
  56. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/exceptions.py +0 -0
  57. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/generate_mutant_pdb.py +0 -0
  58. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/generate_mutants.py +0 -0
  59. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/helpers.py +0 -0
  60. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/np_mutation.py +0 -0
  61. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/mutation/predict_ddG.py +0 -0
  62. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/quick.py +0 -0
  63. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/__init__.py +0 -0
  64. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/assets/ngl.min.js +0 -0
  65. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/data.py +0 -0
  66. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/figures.py +0 -0
  67. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/html_report.py +0 -0
  68. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/ppt_report.py +0 -0
  69. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/report.py +0 -0
  70. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/structure.py +0 -0
  71. {mutadock-2.2.0 → mutadock-2.2.2}/src/mutadock/report/templates/report.html.j2 +0 -0
  72. {mutadock-2.2.0 → mutadock-2.2.2}/tests/__init__.py +0 -0
  73. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_docking/__init__.py +0 -0
  74. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_docking/conftest.py +0 -0
  75. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_docking/test_np_docking.py +0 -0
  76. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_docking/test_vina_dock.py +0 -0
  77. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/__init__.py +0 -0
  78. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/conftest.py +0 -0
  79. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/test_csv_generator.py +0 -0
  80. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/test_csv_sort.py +0 -0
  81. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/test_ddg_calc.py +0 -0
  82. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/test_ddg_protocol.py +0 -0
  83. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/test_ddg_resume.py +0 -0
  84. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/test_generate_mutants.py +0 -0
  85. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/test_helpers.py +0 -0
  86. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_mutation/test_np_mutation.py +0 -0
  87. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_quick.py +0 -0
  88. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_report/__init__.py +0 -0
  89. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_report/conftest.py +0 -0
  90. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_report/test_data.py +0 -0
  91. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_report/test_figures.py +0 -0
  92. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_report/test_html.py +0 -0
  93. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_report/test_ppt.py +0 -0
  94. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_report/test_report.py +0 -0
  95. {mutadock-2.2.0 → mutadock-2.2.2}/tests/test_report/test_structure.py +0 -0
@@ -87,14 +87,14 @@ demo/
87
87
  # AutoDock result files
88
88
  *.dlg
89
89
 
90
- # Docking output PDB files
91
- *_out.pdb
90
+ # Raw multi-pose Vina output (also covered by *.pdbqt above)
91
+ *_out.pdbqt
92
92
 
93
93
  # Per-run log files
94
94
  *_log.txt
95
95
 
96
- # Vina split SDF output
97
- *_ligand_*.sdf
96
+ # Extracted best-pose SDF output
97
+ *_out.sdf
98
98
 
99
99
  # Docking results aggregate
100
100
  docking_results.csv
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.2.2] - 2026-09-19
11
+
12
+ ### Added
13
+ - Local SDF and MOL2 ligand inputs are now validated for a parseable molecule and usable 3-D coordinates before Meeko preparation.
14
+
15
+ ### Changed
16
+ - RDKit is now an explicit Python dependency rather than an implicit requirement of ligand preparation.
17
+ - Installation, AutoSite, matrix-loading, and generated-output guidance is consistent across the README, Sphinx documentation, environment file, installer scripts, and ignore rules.
18
+
19
+ ## [2.2.1] - 2026-09-18
20
+
21
+ ### Changed
22
+ - Updated the PyPI and GitHub README for the 2.2 release series, including current docking outputs, reproducibility controls, resume behavior, input warnings, matrix caching, and subprocess timeout settings.
23
+ - Removed the stale fixed-score example and hard-coded coverage badge from the README.
24
+
10
25
  ## [2.2.0] - 2026-09-18
11
26
 
12
27
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mutadock
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: MUTADOCK is a comprehensive library designed for mutation studies and multiple receptor-ligand docking. Refer to README for more information.
5
5
  Project-URL: Repository, https://github.com/naisarg14/mutadock
6
6
  Project-URL: Issues, https://github.com/naisarg14/mutadock/issues
@@ -27,6 +27,7 @@ Requires-Dist: pdbfixer
27
27
  Requires-Dist: pyarrow
28
28
  Requires-Dist: pyrosetta-installer
29
29
  Requires-Dist: python-pptx
30
+ Requires-Dist: rdkit
30
31
  Requires-Dist: tqdm
31
32
  Provides-Extra: dev
32
33
  Requires-Dist: black>=24.0; extra == 'dev'
@@ -49,7 +50,6 @@ Description-Content-Type: text/markdown
49
50
  [![PyPI version](https://img.shields.io/pypi/v/mutadock.svg)](https://pypi.org/project/mutadock/)
50
51
  [![Python](https://img.shields.io/pypi/pyversions/mutadock.svg)](https://pypi.org/project/mutadock/)
51
52
  [![Docs](https://readthedocs.org/projects/mutadock/badge/?version=latest)](https://mutadock.readthedocs.io/en/latest/)
52
- [![Coverage](https://img.shields.io/badge/coverage-45.45%25-yellow.svg)]()
53
53
 
54
54
  ## Introduction
55
55
 
@@ -72,6 +72,13 @@ MUTADOCK is a comprehensive library for protein mutation studies and multi-recep
72
72
  - Simple CLI for each workflow step
73
73
  - Python API for scripting and integration into existing pipelines
74
74
 
75
+ ### What's new in the 2.2 series
76
+
77
+ - Reproducible docking with a configurable random seed (default `19`) and complete run provenance in `docking_results.csv`
78
+ - Safer input validation, including ligand 3D/hydrogen checks and warnings for multi-model, multi-chain, similar-chain, altloc, and insertion-code structures
79
+ - Resumable mutation and docking workflows plus configurable subprocess timeouts
80
+ - PAM250 and BLOSUM62 bundled in the installed package; additional matrices are cached outside the installation directory
81
+
75
82
 
76
83
  ## System Requirements
77
84
 
@@ -148,15 +155,12 @@ One command takes a **PDB ID**, a **mutation**, and a **ligand code**, and gives
148
155
  md_quick --pdb-id 4QJR --mutation A:386:ASN:HIS --ligand-code imatinib
149
156
  ```
150
157
 
151
- ```
152
- Mutation : ASN-A386-HIS
153
- ΔΔG : -27.30 REU (negative = stabilizing)
154
- Affinity : -5.66 kcal/mol
155
- Report : mdquick_4QJR/reports/report.html
156
- ```
157
-
158
158
  It fetches + cleans the structure, computes the ΔΔG for that single mutation, builds the mutant, fetches the ligand, finds the pocket with AutoSite (or pass `-c config.txt`), docks, and writes the standard `reports/` bundle. Use `-i protein.pdb` for a local structure, `--ligand-file lig.sdf` for a local ligand, or `--ligand-code 2244` / `cid:5291` / `name:aspirin` for PubChem. Requires the `autosite` binary (ADFRsuite) on PATH when no config is given.
159
159
 
160
+ Scores depend on the input structure and protocol, so treat the values printed by
161
+ the demo as results rather than fixed expected output. Pass `--seed` to reproduce
162
+ a docking run exactly.
163
+
160
164
  The staged tools below give you full control over each step.
161
165
 
162
166
  ### 1. Generate mutation candidates
@@ -215,14 +219,21 @@ md_mutate -h # all options
215
219
 
216
220
  Provide exactly one of `-i/--input` (a local `.pdb`/`.cif` file) or `--pdb-id` (a
217
221
  4-character RCSB accession, downloaded automatically). `md_mutate` also warns when
218
- the input contains multiple models, alternate conformations (altlocs), or
219
- insertion codes, since these affect residue numbering.
222
+ the input contains multiple models or chains, similar chain sequences, alternate
223
+ conformations (altlocs), or insertion codes, since these can make chain selection
224
+ and residue numbering ambiguous. Inspect these warnings and isolate the intended
225
+ chain(s) before interpreting results.
220
226
 
221
227
  By default every output file is written next to the input structure. Pass
222
228
  `-o/--output-dir DIR` to collect them in `DIR` instead (created if absent); the
223
229
  paths recorded in `*_mutants.txt` point into `DIR`, so they remain valid input
224
230
  for `md_dock`.
225
231
 
232
+ `md_mutate` appends to its checkpoint CSVs by default and skips completed items,
233
+ so rerunning an interrupted job resumes it. The direct `md_ddg_single`,
234
+ `md_ddg_double`, and `md_ddg_triple` commands also support `--resume`. Use
235
+ `--no-append` when you intentionally want a fresh run.
236
+
226
237
  #### Mutation Output
227
238
 
228
239
  | # | File | Description |
@@ -242,7 +253,7 @@ for `md_dock`.
242
253
  ΔΔG is computed as `score(mutant) − score(wild-type self-mutation reference)`, where **both** sides run the identical repack(+minimization) protocol — so a null WT→WT mutation scores ≈ 0 and the values are not biased toward "stabilizing."
243
254
 
244
255
  - **Units:** `ddG_value` is in **Rosetta Energy Units (REU), not kcal/mol.** A `ddG_kcal` column is also written, and reports show both. REU ≈ but ≠ kcal/mol.
245
- - **Scaling factor:** the REU→kcal/mol factor is **`REU_TO_KCAL_SCALE` in `src/mutadock/mutation/predict_ddG.py`** (default `0.34`, ≈ 1/2.94; the ref2015 `cartesian_ddg` convention, Park et al. 2016). **To change it, edit that constant** or pass `--reu-to-kcal FACTOR` per run.
256
+ - **Scaling factor:** the default REU→kcal/mol factor is `0.34` (≈ 1/2.94; the ref2015 `cartesian_ddg` convention, Park et al. 2016). Override it per run with `--reu-to-kcal FACTOR`; modifying installed package code is not required.
246
257
  - **Protocol (`--protocol`, default `min`):** the recorded protocol is written to a `ddG_protocol` column, and reports flag screening-only runs.
247
258
 
248
259
  ```bash
@@ -304,6 +315,7 @@ Output files are named `{stem}_{WTAA}-{CHAIN}{POS}-{NEWAA}.pdb` (e.g. `protein_A
304
315
  ```bash
305
316
  md_dock -r receptors.txt -l ligands.txt -c config.txt
306
317
  md_dock -r receptors.txt -l ligands.txt -c config.txt -o results/ # collect outputs in results/
318
+ md_dock -r receptors.txt -l ligands.txt -c config.txt --seed 19 # reproducible run
307
319
  md_dock -h # all options
308
320
  ```
309
321
 
@@ -313,17 +325,22 @@ By default docking outputs go to an `out/` folder next to each receptor. Pass
313
325
  `-o/--output-dir DIR` to collect poses, logs, `docking_results.csv`, and the
314
326
  `*_completed.txt` resume file in a single `DIR` instead. Prepared PDBQT files and
315
327
  AutoSite caches still live next to their inputs so they can be reused across runs.
328
+ Completed receptor–ligand pairs are skipped automatically; use
329
+ `--ignore-existing` to dock them again. The default seed is `19`. It can also be
330
+ set as `seed = ...` in the configuration file, while an explicit CLI `--seed`
331
+ takes precedence. The CSV records the search box, exhaustiveness, and seed for
332
+ every result.
316
333
 
317
334
  #### Docking Output
318
335
 
319
336
  | # | Output | Description |
320
337
  |---|--------|-------------|
321
338
  | 1 | PDBQT files | Prepared receptor and ligand files |
322
- | 2 | Log file | Vina output with binding scores per combination |
323
- | 3 | Output PDB | Top 5 docking poses per combination |
324
- | 4 | Output PDBQT | Best pose (Vina split) per combination |
325
- | 5 | Output SDF | Best pose as SDF for visualization |
326
- | 6 | `docking_results.csv` | All affinities tabulated for easy analysis |
339
+ | 2 | `*_log.txt` | Vina output with binding scores per combination |
340
+ | 3 | `*_out.pdbqt` | Raw multi-pose Vina output |
341
+ | 4 | `*_out.sdf` | Extracted best pose for visualization |
342
+ | 5 | `docking_results.csv` | Affinities plus search-box, exhaustiveness, and seed provenance |
343
+ | 6 | `*_completed.txt` | Resume checkpoint containing completed receptor–ligand pairs |
327
344
 
328
345
  ### Reports
329
346
 
@@ -399,10 +416,13 @@ generate_csv("data/4QJR.cif")
399
416
  # Use BLOSUM62 (downloaded automatically if absent)
400
417
  generate_csv("data/4QJR.cif", matrix="BLOSUM62")
401
418
 
402
- # Load a matrix directly
403
- score_dict = load_matrix("data/PAM250") # dict[str, dict[str, int]], 3-letter keys
419
+ # Resolve a bundled or downloadable matrix by name
420
+ score_dict = resolve_matrix("PAM250") # works in source and installed packages
404
421
  score_dict = resolve_matrix("PAM30") # downloads PAM30 from NCBI if needed
405
422
 
423
+ # Or load a custom matrix file directly
424
+ score_dict = load_matrix("/path/to/custom_matrix")
425
+
406
426
  # --- Generate mutant PDB ---
407
427
  from mutadock.mutation.generate_mutant_pdb import generate_pdb
408
428
 
@@ -432,6 +452,7 @@ dock_vina(
432
452
  log_file="vina.log",
433
453
  center=[10.0, 5.0, 20.0],
434
454
  box_size=[20.0, 20.0, 20.0],
455
+ seed=19,
435
456
  )
436
457
  ```
437
458
 
@@ -467,6 +488,17 @@ If NCBI FTP is unreachable, download the matrix manually and use `--matrix-file`
467
488
  md_csv_generator -i protein.pdb --matrix-file /path/to/PAM30
468
489
  ```
469
490
 
491
+ PAM250 and BLOSUM62 are included with MUTADOCK. Other downloaded matrices are
492
+ cached in `~/.cache/mutadock/matrices`; set `MUTADOCK_DATA_DIR` to use a different
493
+ cache directory.
494
+
495
+ **An external preparation or docking command times out**
496
+
497
+ The default limits are 900 seconds for receptor preparation, 1800 seconds for
498
+ AutoSite, and 3600 seconds for Vina. Override them with
499
+ `MUTADOCK_RECEPTOR_PREP_TIMEOUT`, `MUTADOCK_AUTOSITE_TIMEOUT`, and
500
+ `MUTADOCK_VINA_TIMEOUT`, respectively. Set a value to `0` to disable that timeout.
501
+
470
502
  **CIF file not recognized**
471
503
  PDBFixer and BioPython both support `.cif` natively. Make sure the file extension is `.cif` or `.pdb` — other extensions are not accepted.
472
504
 
@@ -4,7 +4,6 @@
4
4
  [![PyPI version](https://img.shields.io/pypi/v/mutadock.svg)](https://pypi.org/project/mutadock/)
5
5
  [![Python](https://img.shields.io/pypi/pyversions/mutadock.svg)](https://pypi.org/project/mutadock/)
6
6
  [![Docs](https://readthedocs.org/projects/mutadock/badge/?version=latest)](https://mutadock.readthedocs.io/en/latest/)
7
- [![Coverage](https://img.shields.io/badge/coverage-45.45%25-yellow.svg)]()
8
7
 
9
8
  ## Introduction
10
9
 
@@ -27,6 +26,13 @@ MUTADOCK is a comprehensive library for protein mutation studies and multi-recep
27
26
  - Simple CLI for each workflow step
28
27
  - Python API for scripting and integration into existing pipelines
29
28
 
29
+ ### What's new in the 2.2 series
30
+
31
+ - Reproducible docking with a configurable random seed (default `19`) and complete run provenance in `docking_results.csv`
32
+ - Safer input validation, including ligand 3D/hydrogen checks and warnings for multi-model, multi-chain, similar-chain, altloc, and insertion-code structures
33
+ - Resumable mutation and docking workflows plus configurable subprocess timeouts
34
+ - PAM250 and BLOSUM62 bundled in the installed package; additional matrices are cached outside the installation directory
35
+
30
36
 
31
37
  ## System Requirements
32
38
 
@@ -103,15 +109,12 @@ One command takes a **PDB ID**, a **mutation**, and a **ligand code**, and gives
103
109
  md_quick --pdb-id 4QJR --mutation A:386:ASN:HIS --ligand-code imatinib
104
110
  ```
105
111
 
106
- ```
107
- Mutation : ASN-A386-HIS
108
- ΔΔG : -27.30 REU (negative = stabilizing)
109
- Affinity : -5.66 kcal/mol
110
- Report : mdquick_4QJR/reports/report.html
111
- ```
112
-
113
112
  It fetches + cleans the structure, computes the ΔΔG for that single mutation, builds the mutant, fetches the ligand, finds the pocket with AutoSite (or pass `-c config.txt`), docks, and writes the standard `reports/` bundle. Use `-i protein.pdb` for a local structure, `--ligand-file lig.sdf` for a local ligand, or `--ligand-code 2244` / `cid:5291` / `name:aspirin` for PubChem. Requires the `autosite` binary (ADFRsuite) on PATH when no config is given.
114
113
 
114
+ Scores depend on the input structure and protocol, so treat the values printed by
115
+ the demo as results rather than fixed expected output. Pass `--seed` to reproduce
116
+ a docking run exactly.
117
+
115
118
  The staged tools below give you full control over each step.
116
119
 
117
120
  ### 1. Generate mutation candidates
@@ -170,14 +173,21 @@ md_mutate -h # all options
170
173
 
171
174
  Provide exactly one of `-i/--input` (a local `.pdb`/`.cif` file) or `--pdb-id` (a
172
175
  4-character RCSB accession, downloaded automatically). `md_mutate` also warns when
173
- the input contains multiple models, alternate conformations (altlocs), or
174
- insertion codes, since these affect residue numbering.
176
+ the input contains multiple models or chains, similar chain sequences, alternate
177
+ conformations (altlocs), or insertion codes, since these can make chain selection
178
+ and residue numbering ambiguous. Inspect these warnings and isolate the intended
179
+ chain(s) before interpreting results.
175
180
 
176
181
  By default every output file is written next to the input structure. Pass
177
182
  `-o/--output-dir DIR` to collect them in `DIR` instead (created if absent); the
178
183
  paths recorded in `*_mutants.txt` point into `DIR`, so they remain valid input
179
184
  for `md_dock`.
180
185
 
186
+ `md_mutate` appends to its checkpoint CSVs by default and skips completed items,
187
+ so rerunning an interrupted job resumes it. The direct `md_ddg_single`,
188
+ `md_ddg_double`, and `md_ddg_triple` commands also support `--resume`. Use
189
+ `--no-append` when you intentionally want a fresh run.
190
+
181
191
  #### Mutation Output
182
192
 
183
193
  | # | File | Description |
@@ -197,7 +207,7 @@ for `md_dock`.
197
207
  ΔΔG is computed as `score(mutant) − score(wild-type self-mutation reference)`, where **both** sides run the identical repack(+minimization) protocol — so a null WT→WT mutation scores ≈ 0 and the values are not biased toward "stabilizing."
198
208
 
199
209
  - **Units:** `ddG_value` is in **Rosetta Energy Units (REU), not kcal/mol.** A `ddG_kcal` column is also written, and reports show both. REU ≈ but ≠ kcal/mol.
200
- - **Scaling factor:** the REU→kcal/mol factor is **`REU_TO_KCAL_SCALE` in `src/mutadock/mutation/predict_ddG.py`** (default `0.34`, ≈ 1/2.94; the ref2015 `cartesian_ddg` convention, Park et al. 2016). **To change it, edit that constant** or pass `--reu-to-kcal FACTOR` per run.
210
+ - **Scaling factor:** the default REU→kcal/mol factor is `0.34` (≈ 1/2.94; the ref2015 `cartesian_ddg` convention, Park et al. 2016). Override it per run with `--reu-to-kcal FACTOR`; modifying installed package code is not required.
201
211
  - **Protocol (`--protocol`, default `min`):** the recorded protocol is written to a `ddG_protocol` column, and reports flag screening-only runs.
202
212
 
203
213
  ```bash
@@ -259,6 +269,7 @@ Output files are named `{stem}_{WTAA}-{CHAIN}{POS}-{NEWAA}.pdb` (e.g. `protein_A
259
269
  ```bash
260
270
  md_dock -r receptors.txt -l ligands.txt -c config.txt
261
271
  md_dock -r receptors.txt -l ligands.txt -c config.txt -o results/ # collect outputs in results/
272
+ md_dock -r receptors.txt -l ligands.txt -c config.txt --seed 19 # reproducible run
262
273
  md_dock -h # all options
263
274
  ```
264
275
 
@@ -268,17 +279,22 @@ By default docking outputs go to an `out/` folder next to each receptor. Pass
268
279
  `-o/--output-dir DIR` to collect poses, logs, `docking_results.csv`, and the
269
280
  `*_completed.txt` resume file in a single `DIR` instead. Prepared PDBQT files and
270
281
  AutoSite caches still live next to their inputs so they can be reused across runs.
282
+ Completed receptor–ligand pairs are skipped automatically; use
283
+ `--ignore-existing` to dock them again. The default seed is `19`. It can also be
284
+ set as `seed = ...` in the configuration file, while an explicit CLI `--seed`
285
+ takes precedence. The CSV records the search box, exhaustiveness, and seed for
286
+ every result.
271
287
 
272
288
  #### Docking Output
273
289
 
274
290
  | # | Output | Description |
275
291
  |---|--------|-------------|
276
292
  | 1 | PDBQT files | Prepared receptor and ligand files |
277
- | 2 | Log file | Vina output with binding scores per combination |
278
- | 3 | Output PDB | Top 5 docking poses per combination |
279
- | 4 | Output PDBQT | Best pose (Vina split) per combination |
280
- | 5 | Output SDF | Best pose as SDF for visualization |
281
- | 6 | `docking_results.csv` | All affinities tabulated for easy analysis |
293
+ | 2 | `*_log.txt` | Vina output with binding scores per combination |
294
+ | 3 | `*_out.pdbqt` | Raw multi-pose Vina output |
295
+ | 4 | `*_out.sdf` | Extracted best pose for visualization |
296
+ | 5 | `docking_results.csv` | Affinities plus search-box, exhaustiveness, and seed provenance |
297
+ | 6 | `*_completed.txt` | Resume checkpoint containing completed receptor–ligand pairs |
282
298
 
283
299
  ### Reports
284
300
 
@@ -354,10 +370,13 @@ generate_csv("data/4QJR.cif")
354
370
  # Use BLOSUM62 (downloaded automatically if absent)
355
371
  generate_csv("data/4QJR.cif", matrix="BLOSUM62")
356
372
 
357
- # Load a matrix directly
358
- score_dict = load_matrix("data/PAM250") # dict[str, dict[str, int]], 3-letter keys
373
+ # Resolve a bundled or downloadable matrix by name
374
+ score_dict = resolve_matrix("PAM250") # works in source and installed packages
359
375
  score_dict = resolve_matrix("PAM30") # downloads PAM30 from NCBI if needed
360
376
 
377
+ # Or load a custom matrix file directly
378
+ score_dict = load_matrix("/path/to/custom_matrix")
379
+
361
380
  # --- Generate mutant PDB ---
362
381
  from mutadock.mutation.generate_mutant_pdb import generate_pdb
363
382
 
@@ -387,6 +406,7 @@ dock_vina(
387
406
  log_file="vina.log",
388
407
  center=[10.0, 5.0, 20.0],
389
408
  box_size=[20.0, 20.0, 20.0],
409
+ seed=19,
390
410
  )
391
411
  ```
392
412
 
@@ -422,6 +442,17 @@ If NCBI FTP is unreachable, download the matrix manually and use `--matrix-file`
422
442
  md_csv_generator -i protein.pdb --matrix-file /path/to/PAM30
423
443
  ```
424
444
 
445
+ PAM250 and BLOSUM62 are included with MUTADOCK. Other downloaded matrices are
446
+ cached in `~/.cache/mutadock/matrices`; set `MUTADOCK_DATA_DIR` to use a different
447
+ cache directory.
448
+
449
+ **An external preparation or docking command times out**
450
+
451
+ The default limits are 900 seconds for receptor preparation, 1800 seconds for
452
+ AutoSite, and 3600 seconds for Vina. Override them with
453
+ `MUTADOCK_RECEPTOR_PREP_TIMEOUT`, `MUTADOCK_AUTOSITE_TIMEOUT`, and
454
+ `MUTADOCK_VINA_TIMEOUT`, respectively. Set a value to `0` to disable that timeout.
455
+
425
456
  **CIF file not recognized**
426
457
  PDBFixer and BioPython both support `.cif` natively. Make sure the file extension is `.cif` or `.pdb` — other extensions are not accepted.
427
458
 
@@ -14,6 +14,8 @@ sys.path.insert(0, os.path.abspath("../src"))
14
14
  project = "MutaDock"
15
15
  copyright = "2026, Naisarg Patel"
16
16
  author = "Naisarg Patel"
17
+ version = "2.2"
18
+ release = "2.2.2"
17
19
 
18
20
  # -- General configuration ---------------------------------------------------
19
21
 
@@ -50,8 +52,6 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
50
52
  # -- Options for HTML output -------------------------------------------------
51
53
 
52
54
  html_theme = "alabaster"
53
- html_static_path = ["_static"]
54
-
55
55
  html_theme_options = {
56
56
  "description": "Mutation analysis and multi-receptor docking toolkit",
57
57
  "github_user": "naisarg14",
@@ -1,5 +1,14 @@
1
1
  MutaDock documentation
2
2
  ======================
3
+
4
+ Release 2.2.2
5
+ -------------
6
+
7
+ MUTADOCK 2.2 adds reproducible docking seeds and run provenance, resumable
8
+ mutation and docking workflows, safer structure and ligand validation, and
9
+ timeouts for external preparation and docking tools. Version 2.2.2 also aligns
10
+ the installation metadata and examples and validates local ligand coordinates.
11
+
3
12
  .. toctree::
4
13
  :maxdepth: 2
5
14
  :caption: Contents:
@@ -50,22 +59,21 @@ How To Guide
50
59
  Installation
51
60
  ^^^^^^^^^^^^
52
61
 
53
- MutaDock has been deployed on PyPi, making installation quick and simple
62
+ MutaDock is published on PyPI, making installation quick and simple:
54
63
 
55
64
  .. code-block::
56
65
 
57
66
  pip install mutadock
58
67
 
59
- The Pyrosetta Installer will be automatically installed but Pyrosetta should be installed using
68
+ The PyRosetta installer is included as a dependency, but PyRosetta itself must
69
+ be installed separately:
60
70
 
61
71
  .. code-block::
62
72
 
63
- md_install_dependencies
73
+ python -c "import pyrosetta_installer; pyrosetta_installer.install_pyrosetta()"
64
74
 
65
- this will install all dependencies including Pyrosetta.
66
-
67
-
68
- * Currently there is a problem with the vina on PyPi, so vina needs to be installed separately, the installation guide can be found at https://autodock-vina.readthedocs.io/en/latest/installation.html
75
+ AutoDock Vina must also be installed separately; follow the `official Vina
76
+ installation guide <https://autodock-vina.readthedocs.io/en/latest/installation.html>`_.
69
77
 
70
78
  Quick demo (md_quick)
71
79
  ^^^^^^^^^^^^^^^^^^^^^^
@@ -83,6 +91,9 @@ name; ``--ligand-file`` takes a local file), locates the pocket with AutoSite (o
83
91
  pass ``-c config.txt``), docks, and writes the standard ``reports/`` bundle into
84
92
  ``mdquick_<id>/`` (or ``-o``). ``-i protein.pdb`` uses a local structure instead
85
93
  of ``--pdb-id``. Requires the ``autosite`` binary on PATH when no config is given.
94
+ Docking uses the reproducible default seed ``19``; pass ``--seed`` to select a
95
+ different seed. A value of ``0`` asks Vina to choose a random, non-reproducible
96
+ seed.
86
97
 
87
98
  Mutation Studies
88
99
  ^^^^^^^^^^^^^^^^
@@ -100,6 +111,17 @@ By default all outputs are written next to the input structure. Pass
100
111
 
101
112
  md_mutate -i protein.pdb -o results/
102
113
 
114
+ The pipeline appends to its checkpoint CSVs by default. Rerunning an interrupted
115
+ job skips completed mutations and resumes the missing work. The direct
116
+ ``md_ddg_single``, ``md_ddg_double``, and ``md_ddg_triple`` commands expose the
117
+ same behavior through ``--resume``. Use ``md_mutate --no-append`` when you
118
+ intentionally want to regenerate all mutation results.
119
+
120
+ MUTADOCK warns when an input contains multiple models or chains, duplicated or
121
+ highly similar chain sequences, alternate conformations, or insertion codes.
122
+ Inspect these warnings and isolate the intended chain or model before interpreting
123
+ residue-numbered results.
124
+
103
125
  Other optional arguments can be changed as required, to check the usage run
104
126
 
105
127
  .. code-block::
@@ -110,8 +132,8 @@ Other optional arguments can be changed as required, to check the usage run
110
132
  reference)`` with the identical protocol on both sides (so a null WT→WT mutation
111
133
  scores ≈ 0). ``ddG_value`` is in **Rosetta Energy Units (REU), not kcal/mol**; a
112
134
  ``ddG_kcal`` column is also written. The REU→kcal/mol factor is
113
- ``REU_TO_KCAL_SCALE`` in ``src/mutadock/mutation/predict_ddG.py`` (default 0.34 ≈
114
- 1/2.94, Park et al. 2016), overridable with ``--reu-to-kcal``. The default
135
+ 0.34 by default (≈ 1/2.94, Park et al. 2016) and is overridable per run with
136
+ ``--reu-to-kcal``; editing installed package code is not required. The default
115
137
  ``--protocol min`` (repack + minimization) is reliable; ``--protocol cartesian``
116
138
  is most accurate; ``--protocol fast`` skips minimization and is **screening
117
139
  only** (absolute values unreliable — its reports carry a warning banner). Use
@@ -186,8 +208,10 @@ it to the ΔΔG stages:
186
208
  **Available matrices.** ``PAM250`` (default) and ``BLOSUM62`` ship with MUTADOCK.
187
209
  Any other matrix name from the `NCBI BLAST FTP
188
210
  <https://ftp.ncbi.nih.gov/blast/matrices/>`_ (e.g. ``PAM30``, ``PAM70``,
189
- ``BLOSUM45``, ``BLOSUM80``) is downloaded automatically into ``data/`` on first
190
- use. A fully custom matrix in NCBI format can be supplied with
211
+ ``BLOSUM45``, ``BLOSUM80``) is downloaded automatically into the user-writable
212
+ ``~/.cache/mutadock/matrices`` directory on first use. Set
213
+ ``MUTADOCK_DATA_DIR`` to choose another cache directory. A fully custom matrix
214
+ in NCBI format can be supplied with
191
215
  ``--matrix-file /path/to/matrix`` (this overrides ``--matrix``).
192
216
 
193
217
  **When to use which.** PAM matrices model accepted point mutations over
@@ -215,18 +239,26 @@ Docking Studies
215
239
  ^^^^^^^^^^^^^^^
216
240
 
217
241
  Docking for multiple receptors and ligands is made simple and efficient by mutadock. The text files containing the names of the receptors and ligands need to be given as input, after that everything is automated. (If md_mutate is used, the text file for receptor is generated automatically)
218
- Every receptor in the receptor file will be docked with every ligand in the ligand file. A standard Vina configuration file or an AutoSIte prediction output is required.
242
+ Every receptor in the receptor file will be docked with every ligand in the ligand file. Supply a standard Vina configuration file or an existing AutoSite prediction, or omit both to run AutoSite automatically for each receptor.
219
243
  Example:
220
244
 
221
245
  .. code-block::
222
246
 
223
247
  md_dock -r receptors.txt -l ligands.txt -c config.txt
248
+ md_dock -r receptors.txt -l ligands.txt -c config.txt --seed 19
224
249
 
225
250
  By default docking outputs go to an ``out/`` folder next to each receptor. Pass
226
251
  ``-o/--output-dir DIR`` to collect poses, logs, ``docking_results.csv``, and the
227
252
  resume file in a single ``DIR`` instead. Prepared PDBQT files and AutoSite caches
228
253
  still live next to their inputs so they can be reused across runs.
229
254
 
255
+ Completed receptor-ligand pairs are skipped automatically using the
256
+ ``*_completed.txt`` checkpoint. Pass ``--ignore-existing`` to dock them again.
257
+ The default Vina seed is ``19``. It can also be set with ``seed = ...`` in a
258
+ configuration file; an explicit command-line ``--seed`` takes precedence with a
259
+ visible warning. ``docking_results.csv`` records the box center, box size,
260
+ exhaustiveness, and seed for every result so a run can be reproduced.
261
+
230
262
  .. code-block::
231
263
 
232
264
  md_dock -r receptors.txt -l ligands.txt -c config.txt -o results/
@@ -249,20 +281,20 @@ The output of md_dock with their description is in the table below:
249
281
  - PDBQT files
250
282
  - The receptors and ligands will be converted to PDBQT files for AutoDock Vina.
251
283
  * - 2.
252
- - Output Log
284
+ - ``*_log.txt``
253
285
  - The output of AutoDock Vina with the docking scores will be stored in a log file for each combination.
254
286
  * - 3.
255
- - Output PDB
256
- - The output of AutoDock Vina with the 5 best docking poses will be stored in a PDB file for each combination.
287
+ - ``*_out.pdbqt``
288
+ - Raw multi-pose output written by AutoDock Vina for each combination.
257
289
  * - 4.
258
- - Output PDBQT
259
- - The output of AutoDock Vina Split with the best pose will be stored in a PDBQT file for each combination.
290
+ - ``*_out.sdf``
291
+ - The extracted best pose in SDF format for visualization.
260
292
  * - 5.
261
- - Output SDF
262
- - The best pose after docking will be stored in a SDF file for visualization and better usability.
293
+ - ``docking_results.csv``
294
+ - Affinities and the search-box, exhaustiveness, and seed provenance for every successful combination.
263
295
  * - 6.
264
- - Docking Results CSV
265
- - All the docking affinities are tabulated in a CSV to make analysis trivial.
296
+ - ``*_completed.txt``
297
+ - Resume checkpoint containing completed receptor-ligand combinations.
266
298
 
267
299
 
268
300
  Choosing the docking box
@@ -277,7 +309,7 @@ how they interact avoids the most common surprises.
277
309
  ``center_y``, ``center_z`` (box center), ``size_x``, ``size_y``, ``size_z``
278
310
  (box dimensions in Å — these are independent, so the box may be
279
311
  **non-cubic**), plus ``exhaustiveness`` (default 32), ``n_poses`` (20),
280
- ``n_poses_write`` (5) and ``overwrite``. Lines beginning with ``#`` are
312
+ ``n_poses_write`` (5), ``overwrite``, and ``seed`` (19). Lines beginning with ``#`` are
281
313
  ignored. Use this when you already know the pocket, want a reproducible box, or
282
314
  need to tune the search. **Watch out:** any omitted ``center_*`` key silently
283
315
  defaults to ``0.0`` — a config without an explicit center places an empty box
@@ -292,6 +324,7 @@ how they interact avoids the most common surprises.
292
324
  size_y = 24
293
325
  size_z = 24
294
326
  exhaustiveness = 32
327
+ seed = 19
295
328
 
296
329
  * **``-a autosite.pdb`` — a fixed AutoSite cluster.** Pass a cluster PDB that
297
330
  AutoSite already produced. MUTADOCK sets the center to the cluster's geometric
@@ -307,12 +340,23 @@ how they interact avoids the most common surprises.
307
340
  error asking for one of the options above. Prefer this when docking mutants
308
341
  whose pockets may shift, since each receptor gets its own box.
309
342
 
310
- **How ``-c`` and ``-a`` interact.** If you pass both, AutoSite wins for the
311
- *geometry* — the cluster's center and cube override whatever ``center_*`` /
312
- ``size_*`` were in the config — but the config's **search parameters**
313
- (``exhaustiveness``, ``n_poses``, ``n_poses_write``, ``overwrite``) still apply.
314
- This lets you take the box from AutoSite while keeping a tuned search from your
315
- config.
343
+ **Do not combine ``-c`` and ``-a``.** They are mutually exclusive sources of
344
+ docking-box geometry, and MUTADOCK rejects a command that supplies both instead
345
+ of silently choosing one.
346
+
347
+ External-tool timeouts
348
+ ^^^^^^^^^^^^^^^^^^^^^^
349
+
350
+ MUTADOCK prevents a hung external process from blocking an entire batch. The
351
+ default limits are 900 seconds for receptor preparation, 1800 seconds for
352
+ AutoSite, and 3600 seconds for Vina. Override them with
353
+ ``MUTADOCK_RECEPTOR_PREP_TIMEOUT``, ``MUTADOCK_AUTOSITE_TIMEOUT``, and
354
+ ``MUTADOCK_VINA_TIMEOUT``, respectively. Set a value to ``0`` to disable that
355
+ timeout.
356
+
357
+ Ligand preparation adds hydrogens with 3-D coordinates before Meeko conversion.
358
+ Inputs without usable 3-D coordinates are rejected with an actionable error
359
+ instead of producing a misleading docking result.
316
360
 
317
361
  Reports
318
362
  ^^^^^^^
@@ -345,29 +389,38 @@ All CLI Scripts
345
389
  - **Command**
346
390
  - **Description**
347
391
  * - 1.
392
+ - md_quick
393
+ - Runs mutation, mutant generation, ligand acquisition, docking, and reporting as a one-command workflow
394
+ * - 2.
348
395
  - md_mutate
349
396
  - Predicts the best mutation of the given protein
350
- * - 2.
397
+ * - 3.
351
398
  - md_dock
352
399
  - Docked all combinations from a list of receptors and ligands
353
- * - 3.
400
+ * - 4.
354
401
  - md_vina_dock
355
402
  - CLI for AutoDock Vina
356
- * - 4.
403
+ * - 5.
357
404
  - md_csv_generator
358
405
  - Generates all possible mutations for a protein and also the mutations possible according to PAM Matrix
359
- * - 5.
406
+ * - 6.
360
407
  - md_csv_sort
361
408
  - Can sort any CSV file according to the column name or number chosen
362
- * - 6.
409
+ * - 7.
363
410
  - md_ddg_single
364
411
  - Calculates single ddG values for a given CSV of mutations
365
- * - 7.
412
+ * - 8.
366
413
  - md_ddg_double
367
414
  - Calculates double ddG values for all combinations using a given CSV of mutations
368
- * - 8.
415
+ * - 9.
369
416
  - md_ddg_triple
370
417
  - Calculates triple ddG values for all combinations using a given CSV of mutations
418
+ * - 10.
419
+ - md_generate_pdb
420
+ - Generates independent or compound mutant PDB files without running ΔΔG scoring
421
+ * - 11.
422
+ - md_report
423
+ - Builds HTML and PowerPoint reports from an existing run directory
371
424
 
372
425
 
373
426
  Applications
@@ -39,5 +39,6 @@ dependencies:
39
39
  # AutoSite (ADFRsuite), used by `md_quick` for automatic pocket detection
40
40
  # when no config file is given, is not packaged on conda-forge/PyPI. Download
41
41
  # it separately from https://ccsb.scripps.edu/adfr/downloads/ and put its
42
- # `bin/` directory on PATH, or always pass `-c config.txt` / `--ligand-file`
43
- # with an explicit box to skip it.
42
+ # `bin/` directory on PATH, or pass `-c config.txt` with an explicit box to
43
+ # skip automatic pocket detection. Selecting a ligand with `--ligand-file`
44
+ # does not define the docking box.
@@ -10,7 +10,7 @@ echo "==> Activating virtual environment..."
10
10
  # shellcheck disable=SC1091
11
11
  source "$VENV_DIR/bin/activate"
12
12
 
13
- echo "==> Installing mutadock and its dependencies..."
13
+ echo "==> Installing MUTADOCK and its declared Python dependencies..."
14
14
  python -m pip install --upgrade pip
15
15
  python -m pip install .
16
16
 
@@ -20,3 +20,5 @@ python -c 'import pyrosetta_installer; pyrosetta_installer.install_pyrosetta()'
20
20
  echo ""
21
21
  echo "Installation complete."
22
22
  echo "Activate the environment with: source $VENV_DIR/bin/activate"
23
+ echo "AutoDock Vina and AutoSite are external tools and are not installed by this script."
24
+ echo "For the complete native stack, prefer the documented conda or Docker installation."
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "mutadock"
7
- version = "2.2.0"
7
+ version = "2.2.2"
8
8
  authors = [
9
9
  {name = "Naisarg Patel", email = "naisarg.patel14@hotmail.com"}
10
10
  ]
@@ -18,9 +18,10 @@ dependencies = [
18
18
  'meeko',
19
19
  'numpy',
20
20
  'openmm',
21
- 'pdbfixer',
22
- 'pyrosetta-installer',
23
- 'tqdm',
21
+ 'pdbfixer',
22
+ 'pyrosetta-installer',
23
+ 'rdkit',
24
+ 'tqdm',
24
25
  'pyarrow',
25
26
  'pandas',
26
27
  'matplotlib',
@@ -27,4 +27,4 @@ Top-level package exposing two subpackages:
27
27
  preparation and batch docking workflows.
28
28
  """
29
29
 
30
- __version__ = "2.2.0"
30
+ __version__ = "2.2.2"
@@ -145,7 +145,7 @@ def read_pdb_file(file_path: str) -> list[dict[str, Any]]:
145
145
  List of atom dicts.
146
146
 
147
147
  Raises:
148
- PDBFileError: If the file cannot be read or parsed.
148
+ mutadock.docking.exceptions.PDBFileError: If the file cannot be read or parsed.
149
149
  """
150
150
  import re
151
151
 
@@ -189,7 +189,7 @@ def calculate_geometric_center(pdb_file: str) -> tuple[float, float, float]:
189
189
  A 3-tuple ``(cx, cy, cz)`` of mean coordinates.
190
190
 
191
191
  Raises:
192
- PDBFileError: If the PDB file cannot be parsed.
192
+ mutadock.docking.exceptions.PDBFileError: If the PDB file cannot be parsed.
193
193
  """
194
194
  atoms = read_pdb_file(pdb_file)
195
195
  num_atoms = len(atoms)
@@ -214,7 +214,7 @@ def calculate_radius(pdb_file: str) -> float:
214
214
  Max distance in Ångströms.
215
215
 
216
216
  Raises:
217
- PDBFileError: If the PDB file cannot be parsed.
217
+ mutadock.docking.exceptions.PDBFileError: If the PDB file cannot be parsed.
218
218
  """
219
219
  import math
220
220
 
@@ -420,6 +420,23 @@ def fetch_ligand(
420
420
  return str(dest)
421
421
 
422
422
 
423
+ def _require_3d_ligand(mol: Any, source: str) -> None:
424
+ """Validate that an RDKit ligand is non-empty and has a 3-D conformer."""
425
+ if mol is None or mol.GetNumAtoms() == 0:
426
+ raise LigandPreparationError(
427
+ f"Ligand '{source}' does not contain a parseable molecule."
428
+ )
429
+ if mol.GetNumConformers() == 0:
430
+ raise LigandPreparationError(
431
+ f"Ligand '{source}' has no coordinates; provide a 3-D SDF or MOL2 file."
432
+ )
433
+ if not mol.GetConformer().Is3D():
434
+ raise LigandPreparationError(
435
+ f"Ligand '{source}' contains only 2-D coordinates; provide a 3-D "
436
+ "SDF or MOL2 file."
437
+ )
438
+
439
+
423
440
  def prepare_ligand(in_file: str, out_file: Optional[str] = None) -> str:
424
441
  """Convert an SDF or MOL2 ligand file to PDBQT format using meeko.
425
442
 
@@ -434,33 +451,28 @@ def prepare_ligand(in_file: str, out_file: Optional[str] = None) -> str:
434
451
  Raises:
435
452
  LigandPreparationError: If preparation fails for any reason.
436
453
  """
437
- try:
438
- import sys
454
+ suffix = Path(in_file).suffix.lower()
455
+ if suffix not in {".sdf", ".mol2"}:
456
+ raise LigandPreparationError("Input file is not in SDF or MOL2 format.")
439
457
 
458
+ try:
440
459
  from meeko import MoleculePreparation, PDBQTWriterLegacy
441
460
  from rdkit import Chem
442
- except ModuleNotFoundError:
443
- msg = "Error with importing modules for preparing ligand files for Docking.\n"
444
- msg += "Easiest way to fix this is to install meeko and rdkit using the following command:\n\n"
445
- msg += "python -m pip install meeko rdkit\n"
446
- msg += "If you already have meeko and rdkit installed, please check the installation.\n"
447
- msg += "If the problem persists, please create a github issue or contact developer at naisarg.patel14@hotmail.com"
448
- logger.error(msg)
449
- sys.exit(2)
461
+ except ModuleNotFoundError as e:
462
+ raise LigandPreparationError(
463
+ "Ligand preparation requires meeko and RDKit. Install MUTADOCK's "
464
+ "declared dependencies or run 'python -m pip install meeko rdkit'."
465
+ ) from e
450
466
 
451
467
  if out_file is None:
452
- if in_file.endswith(".sdf"):
453
- out_file = f"{in_file.removesuffix('.sdf')}.pdbqt"
454
- elif in_file.endswith(".mol2"):
455
- out_file = f"{in_file.removesuffix('.mol2')}.pdbqt"
456
- else:
457
- raise LigandPreparationError("Input file is not in SDF or MOL2 format.")
468
+ out_file = str(Path(in_file).with_suffix(".pdbqt"))
458
469
 
459
470
  try:
460
- if in_file.endswith(".sdf"):
471
+ if suffix == ".sdf":
461
472
  mol = Chem.SDMolSupplier(in_file)[0]
462
- if in_file.endswith(".mol2"):
473
+ else:
463
474
  mol = Chem.MolFromMol2File(in_file)
475
+ _require_3d_ligand(mol, in_file)
464
476
 
465
477
  # addCoords=True is REQUIRED. Without it RDKit adds the hydrogens as
466
478
  # topology only, with no 3D coordinates, and meeko then writes every one
@@ -873,7 +885,7 @@ def dock_vina(
873
885
 
874
886
  Raises:
875
887
  ConfigError: If the config file cannot be read.
876
- PDBFileError: If the autosite PDB cannot be parsed.
888
+ mutadock.docking.exceptions.PDBFileError: If the autosite PDB cannot be parsed.
877
889
  DockingRunError: If the Vina subprocess exits with a non-zero code.
878
890
  """
879
891
  if config is not None:
@@ -74,7 +74,7 @@ def generate_csv(
74
74
  ``(out_op, out_all)`` paths.
75
75
 
76
76
  Raises:
77
- PDBFileError: If the PDB file cannot be read.
77
+ mutadock.mutation.exceptions.PDBFileError: If the PDB file cannot be read.
78
78
  CSVGenerationError: If the PDB file contains no residues.
79
79
  MutationError: If the matrix cannot be loaded or downloaded.
80
80
  """
@@ -160,7 +160,7 @@ def get_residues(file: str) -> dict[int, tuple[str, int, str]]:
160
160
  Mapping of sequential index to ``(chain_id, position, residue_name)``.
161
161
 
162
162
  Raises:
163
- PDBFileError: If the file is not found.
163
+ mutadock.mutation.exceptions.PDBFileError: If the file is not found.
164
164
  """
165
165
  residues: dict[int, tuple[str, int, str]] = {}
166
166
  count = 1
@@ -331,9 +331,12 @@ class TestPrepareLigand(unittest.TestCase):
331
331
 
332
332
  shutil.rmtree(self.tmpdir, ignore_errors=True)
333
333
 
334
- def _stubs(self, pdbqt_string="PDBQT_DATA"):
335
- mock_mol = MagicMock()
336
- mock_chem = MagicMock()
334
+ def _stubs(self, pdbqt_string="PDBQT_DATA"):
335
+ mock_mol = MagicMock()
336
+ mock_mol.GetNumAtoms.return_value = 2
337
+ mock_mol.GetNumConformers.return_value = 1
338
+ mock_mol.GetConformer.return_value.Is3D.return_value = True
339
+ mock_chem = MagicMock()
337
340
  mock_chem.SDMolSupplier.return_value.__getitem__ = MagicMock(
338
341
  return_value=mock_mol
339
342
  )
@@ -382,14 +385,43 @@ class TestPrepareLigand(unittest.TestCase):
382
385
  vina_helper.prepare_ligand(in_file)
383
386
  self.assertTrue(Path(expected_out).is_file())
384
387
 
385
- def test_exception_raises_ligand_preparation_error(self):
388
+ def test_exception_raises_ligand_preparation_error(self):
386
389
  in_file = str(self.tmpdir / "lig.sdf")
387
390
  Path(in_file).write_text("mol")
388
391
  meeko_stub, rdkit_stub = self._stubs()
389
392
  rdkit_stub.Chem.AddHs.side_effect = RuntimeError("bad mol")
390
393
  with patch.dict(sys.modules, self._modules(meeko_stub, rdkit_stub)):
391
394
  with self.assertRaises(LigandPreparationError):
392
- vina_helper.prepare_ligand(in_file)
395
+ vina_helper.prepare_ligand(in_file)
396
+
397
+ def test_unparseable_local_ligand_is_rejected(self):
398
+ in_file = str(self.tmpdir / "bad.sdf")
399
+ Path(in_file).write_text("not an sdf")
400
+ meeko_stub, rdkit_stub = self._stubs()
401
+ rdkit_stub.Chem.SDMolSupplier.return_value.__getitem__.return_value = None
402
+ with patch.dict(sys.modules, self._modules(meeko_stub, rdkit_stub)):
403
+ with self.assertRaisesRegex(LigandPreparationError, "parseable"):
404
+ vina_helper.prepare_ligand(in_file)
405
+
406
+ def test_local_ligand_without_coordinates_is_rejected(self):
407
+ in_file = str(self.tmpdir / "flat.sdf")
408
+ Path(in_file).write_text("mol")
409
+ meeko_stub, rdkit_stub = self._stubs()
410
+ mol = rdkit_stub.Chem.SDMolSupplier.return_value.__getitem__.return_value
411
+ mol.GetNumConformers.return_value = 0
412
+ with patch.dict(sys.modules, self._modules(meeko_stub, rdkit_stub)):
413
+ with self.assertRaisesRegex(LigandPreparationError, "no coordinates"):
414
+ vina_helper.prepare_ligand(in_file)
415
+
416
+ def test_local_ligand_with_2d_coordinates_is_rejected(self):
417
+ in_file = str(self.tmpdir / "flat.sdf")
418
+ Path(in_file).write_text("mol")
419
+ meeko_stub, rdkit_stub = self._stubs()
420
+ mol = rdkit_stub.Chem.SDMolSupplier.return_value.__getitem__.return_value
421
+ mol.GetConformer.return_value.Is3D.return_value = False
422
+ with patch.dict(sys.modules, self._modules(meeko_stub, rdkit_stub)):
423
+ with self.assertRaisesRegex(LigandPreparationError, "2-D coordinates"):
424
+ vina_helper.prepare_ligand(in_file)
393
425
 
394
426
  def test_addhs_requests_coordinates(self):
395
427
  """AddHs MUST pass addCoords=True.
@@ -18,7 +18,7 @@ if errorlevel 1 (
18
18
  exit /b 1
19
19
  )
20
20
 
21
- echo =^> Installing mutadock and its dependencies...
21
+ echo =^> Installing MUTADOCK and its declared Python dependencies...
22
22
  python -m pip install --upgrade pip
23
23
  python -m pip install .
24
24
  if errorlevel 1 (
@@ -36,4 +36,6 @@ if errorlevel 1 (
36
36
  echo.
37
37
  echo Installation complete.
38
38
  echo Activate the environment with: %VENV_DIR%\Scripts\activate.bat
39
+ echo AutoDock Vina and AutoSite are external tools and are not installed by this script.
40
+ echo For the complete native stack, prefer the documented conda or Docker installation.
39
41
  pause
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes