Skip to content

Commit c7f2703

Browse files
authored
Merge pull request #174 from talagayev/update_cli
Addition of CLI
2 parents 55457a8 + caa8c50 commit c7f2703

File tree

11 files changed

+160
-26
lines changed

11 files changed

+160
-26
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ talagayev, NDoering99
3131
- Fixes numpy error in due current incompatbility with parmed (2025-10-19, PR #160)
3232

3333
### Changed
34+
- Changed the entry points to be bundled in 'cli.py' (2026-01-19, PR #174)
3435
- Transition to `Ruff` linting with `Black` style (2025-10-20, PR #161)
35-
-
36+
3637
## Version 1.1.1
3738

3839
### Authors

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ After installation, activate the conda environment:
8383

8484
Start **OpenMMDL Setup** by executing the command:
8585

86-
openmmdl_setup
86+
openmmdl setup
8787

8888
The **OpenMMDL Setup** interface is displayed through a web browser, but it is still
8989
a single-user desktop application, not a web application. It should
@@ -118,7 +118,7 @@ Setup. The SDF file name should be consistent with the input in the setup
118118

119119
#### Command line example with ligand
120120

121-
openmmdl_simulation -f {path/to/folder_name} -t {path/to/topology} -s {path/to/script} -l {path/to/ligand}
121+
openmmdl simulation -f {path/to/folder_name} -t {path/to/topology} -s {path/to/script} -l {path/to/ligand}
122122

123123
## OpenMMDL Analysis
124124

@@ -175,7 +175,7 @@ Start the analysis with the following Inputs:
175175

176176
#### Command line example with default values
177177

178-
openmmdl_analysis -t {path/to/topology} -d {path/to/trajectory} -n {Ligand_name}
178+
openmmdl analysis -t {path/to/topology} -d {path/to/trajectory} -n {Ligand_name}
179179

180180

181181
#### Visualization
@@ -185,7 +185,7 @@ For the visualization of your complex with interaction pointclouds you can use N
185185

186186
### Usage
187187
```
188-
openmmdl_visualization
188+
openmmdl visualization
189189
```
190190
#### Optional:
191191
--type = Software you wish to visualize openmmdl interactions with. Options: nglview, pymol. Default: nglview

docs/openmmdl_analysis.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ Application
5050
An example of how a command line input for **OpenMMDL Analysis** should look like is:
5151

5252
.. code-block:: text
53-
openmmdl_analysis -t topology.pdb -d trajectory.dcd -l ligand.sdf -n 'LIG'
53+
openmmdl analysis -t topology.pdb -d trajectory.dcd -l ligand.sdf -n 'LIG'
5454
5555
If you need help with the command line input, you can always just use:
5656

5757
.. code-block:: text
58-
openmmdl_analysis -h all
58+
openmmdl analysis -h all
5959
6060
Results
6161
------------------------------
@@ -110,7 +110,7 @@ Furthermore the visualization will display all waters that are involved in formi
110110
Open the visualization using the following command:
111111

112112
.. code-block:: text
113-
openmmdl_visualization
113+
openmmdl visualization
114114
115115
The command will open a prepared jupyter notebook in your browser.
116116
You will need to edit the following variables in the notebook (please note that the paths to the files need to be the absolute file paths):

docs/openmmdl_setup.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Now that we have activated the `openmmdl` environment we can start **OpenMMDL Se
1818

1919
.. code-block:: text
2020
21-
openmmdl_setup
21+
openmmdl setup
2222
2323
This will open the **OpenMMDL Setup**, which you can use for the creation of the input files for **OpenMMDL Simulation**.
2424

docs/openmmdl_simulation.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ An example of how a command line of **OpenMMDL Simulation** should look is:
3838

3939
.. code-block:: text
4040
41-
openmmdl_simulation -f {path/to/folder_name} -t {path/to/topology} -s {path/to/script} -l {path/to/ligand}
41+
openmmdl simulation -f {path/to/folder_name} -t {path/to/topology} -s {path/to/script} -l {path/to/ligand}
4242
4343
4444
For help during the usage of **OpenMMDL Simulation** use the following command line:
4545

4646
.. code-block:: text
4747
48-
openmmdl_simulation -h all
48+
openmmdl simulation -h all
4949
5050
Running OpenMMDL Simulation test simulations
5151
------------------------------
@@ -55,13 +55,13 @@ There are two Systems prepared for the testing of the simulation.
5555

5656
.. code-block:: text
5757
58-
openmmdl_simulation -f 6b73_testing_simulation -t ~/OpenMMDL/openmmdl_simulation/testing_sytems/6b73_membrane/6b73-moe-processed_openMMDL.pdb -s ~/OpenMMDL/openmmdl_simulation/testing_sytems/6b73_membrane/6b73_simulation.py -l ~/OpenMMDL/openmmdl_simulation/testing_sytems/6b73_membrane/6b73_lig.sdf
58+
openmmdl simulation -f 6b73_testing_simulation -t ~/OpenMMDL/openmmdl_simulation/testing_sytems/6b73_membrane/6b73-moe-processed_openMMDL.pdb -s ~/OpenMMDL/openmmdl_simulation/testing_sytems/6b73_membrane/6b73_simulation.py -l ~/OpenMMDL/openmmdl_simulation/testing_sytems/6b73_membrane/6b73_lig.sdf
5959
6060
2: A 10ns simulation of the 5WYZ Protein-ligand complex with TIP3P water. To run the testing of 5WYZ enter the following command line:
6161

6262
.. code-block:: text
6363
64-
openmmdl_simulation -f 5wyz_testing_simulation -t ~/OpenMMDL/openmmdl_simulation/testing_sytems/5wyz_solvent/5wyz-moe-processed_openMMDL.pdb -s ~/OpenMMDL/openmmdl_simulation/testing_sytems/5wyz_solvent/5wyz_simulation.py -l ~/OpenMMDL/openmmdl_simulation/testing_sytems/5wyz_solvent/5VF.sdf
64+
openmmdl simulation -f 5wyz_testing_simulation -t ~/OpenMMDL/openmmdl_simulation/testing_sytems/5wyz_solvent/5wyz-moe-processed_openMMDL.pdb -s ~/OpenMMDL/openmmdl_simulation/testing_sytems/5wyz_solvent/5wyz_simulation.py -l ~/OpenMMDL/openmmdl_simulation/testing_sytems/5wyz_solvent/5VF.sdf
6565
6666
Each of the command lines should generate a folder, where the script and the input data will be moved and further perform a MD simulation and postprocessing of the systems.
6767

docs/tutorial_amber_path.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
Introduction
55
------------------
66

7-
OpenMM enables users to perform molecular dynamics (MD) simulations using AMBER topology (`.prmtop`) and coordinate (`.inpcrd`) files as input. However, obtaining these essential Amber files can be a daunting task for users unfamiliar with Amber commands and Bash scripting. To address this challenge, OpenMMDL-Setup provides a user-friendly interface, streamlining the process of generating the required Amber files for subsequent MD simulations.
7+
OpenMM enables users to perform molecular dynamics (MD) simulations using AMBER topology (`.prmtop`) and coordinate (`.inpcrd`) files as input. However, obtaining these essential Amber files can be a daunting task for users unfamiliar with Amber commands and Bash scripting. To address this challenge, OpenMMDL Setup provides a user-friendly interface, streamlining the process of generating the required Amber files for subsequent MD simulations.
88

9-
In this tutorial, we will use the mu opioid receptor (PDB ID: 8EFO) as an illustrative example to provide a comprehensive, step-by-step guide on configuring and initiating an MD simulation using Amber files prepared by OpenMMDL-Setup.
9+
In this tutorial, we will use the mu opioid receptor (PDB ID: 8EFO) as an illustrative example to provide a comprehensive, step-by-step guide on configuring and initiating an MD simulation using Amber files prepared by OpenMMDL Setup.
1010

11-
Starting OpenMMDL-Setup
11+
Starting OpenMMDL Setup
1212
------------------------------
1313
We start the tutorial by creating an folder to store input files and facilitate the MD simulation.
1414

@@ -18,7 +18,7 @@ Create a new folder we enter the following command lines in the terminal:
1818
1919
mkdir openmmdl_amber_tutorial
2020
21-
Copy the receptor and ligand PDB files from `/openmmdl/openmmdl-simulation/tuturial_systems/amber_path/8efo_membrane` into the newly created folder:
21+
Copy the receptor and ligand PDB files from `/openmmdl/openmmdl_simulation/tutorial_systems/amber_path/8efo_membrane` into the newly created folder:
2222

2323
.. code-block:: text
2424
@@ -33,11 +33,11 @@ Activate the OpenMMDL environment by entering the following command:
3333
3434
conda activate openmmdl
3535
36-
Launch OpenMMDL-Setup:
36+
Launch OpenMMDL Setup:
3737

3838
.. code-block:: text
3939
40-
openmmdl_setup
40+
openmmdl setup
4141
4242
Selecting the Amber Path
4343
------------------------------
@@ -228,4 +228,4 @@ Remember to replace the slurm configuration and environment `openmmdl` path with
228228

229229
.. code-block:: text
230230
231-
sbatch run_slurm.sh
231+
sbatch run_slurm.sh

docs/tutorial_pdb_path.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Now that we have activated the openmmdl environment we can start OpenMMDL-Setup.
2828

2929
.. code-block:: text
3030
31-
openmmdl_setup
31+
openmmdl setup
3232
3333
3434
Selecting Input Files
@@ -184,7 +184,7 @@ For this enter the following command
184184

185185
.. code-block:: text
186186
187-
openmmdl-simulation -f tutorial_simulation -s OpenMMDL_Simulation.py -t 5wyz-processed_openMMDL.pdb -l 5VF.sdf
187+
openmmdl simulation -f tutorial_simulation -s OpenMMDL_Simulation.py -t 5wyz-processed_openMMDL.pdb -l 5VF.sdf
188188
189189
By entering the command we create a folder called tutorial_simulation, where the Output of the MD simulation will appear.
190190

openmmdl/__main__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from __future__ import annotations
2+
3+
from openmmdl.cli.cli import main
4+
5+
if __name__ == "__main__":
6+
raise SystemExit(main())

openmmdl/cli/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

openmmdl/cli/cli.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
from __future__ import annotations
2+
3+
import argparse
4+
import importlib
5+
import sys
6+
from typing import Dict, List, Tuple
7+
8+
COMMANDS: Dict[str, LeafCommand] = {
9+
"setup": (
10+
"openmmdl.openmmdl_setup.openmmdlsetup:main",
11+
"Start the OpenMMDL setup UI (prepare inputs for simulation)",
12+
),
13+
"simulation": (
14+
"openmmdl.openmmdl_simulation.openmmdlsimulation:main",
15+
"Run OpenMM protein-ligand MD simulation",
16+
),
17+
"analysis": (
18+
"openmmdl.openmmdl_analysis.openmmdlanalysis:main",
19+
"Analyze an OpenMMDL MD trajectory",
20+
),
21+
"visualization": (
22+
"openmmdl.openmmdl_analysis.visualization.visualization:run_visualization",
23+
"Launch the visualization notebook",
24+
),
25+
}
26+
27+
28+
HELP_ALIASES = {"--help", "-h", "help", "-help"}
29+
30+
31+
def _build_top_parser() -> argparse.ArgumentParser:
32+
parser = argparse.ArgumentParser(
33+
prog="openmmdl",
34+
description="OpenMMDL command-line interface.",
35+
formatter_class=argparse.RawTextHelpFormatter,
36+
)
37+
38+
# We add subparsers only so argparse prints a clean command list in help.
39+
sub = parser.add_subparsers(dest="command", metavar="<command>")
40+
for name, (_, short_help) in COMMANDS.items():
41+
sub.add_parser(name, help=short_help)
42+
43+
return parser
44+
45+
46+
def _normalize_help_tokens(argv: List[str]) -> List[str]:
47+
"""
48+
Normalize 'help' and '-help' to '--help'
49+
"""
50+
if not argv:
51+
return argv
52+
53+
# Top-level help aliases
54+
if argv[0] in {"help", "-help"}:
55+
return ["--help", *argv[1:]]
56+
57+
# Command-level help aliases (2nd token)
58+
if len(argv) >= 2 and argv[1] in {"help", "-help"}:
59+
return [argv[0], "--help", *argv[2:]]
60+
61+
return argv
62+
63+
64+
def _run_target(target: str, forwarded: List[str], prog: str) -> int:
65+
"""
66+
Import target and call either:
67+
- module:function (callable)
68+
- module (expects main())
69+
Forward argv via sys.argv.
70+
"""
71+
old_argv = sys.argv
72+
sys.argv = [prog, *forwarded]
73+
try:
74+
if ":" in target:
75+
mod_name, func_name = target.split(":", 1)
76+
mod = importlib.import_module(mod_name)
77+
fn = getattr(mod, func_name, None)
78+
if fn is None or not callable(fn):
79+
raise RuntimeError(f"Module '{mod_name}' does not expose callable '{func_name}'.")
80+
rc = fn()
81+
return 0 if rc is None else int(rc)
82+
83+
mod = importlib.import_module(target)
84+
if not hasattr(mod, "main"):
85+
raise RuntimeError(
86+
f"Module '{target}' does not expose a main() function. "
87+
"Add def main(argv=None) and call it from __main__."
88+
)
89+
rc = mod.main() # type: ignore[attr-defined]
90+
return 0 if rc is None else int(rc)
91+
finally:
92+
sys.argv = old_argv
93+
94+
95+
def main(argv: List[str] | None = None) -> int:
96+
"""
97+
Dispatch: openmmdl <command> [args...]
98+
"""
99+
if argv is None:
100+
argv = sys.argv[1:]
101+
102+
argv = _normalize_help_tokens(argv)
103+
104+
# Top-level help
105+
if not argv or argv[0] in HELP_ALIASES:
106+
_build_top_parser().print_help()
107+
return 0
108+
109+
command = argv[0]
110+
if command not in COMMANDS:
111+
sys.stderr.write(f"Unknown command: {command!r}\n\n")
112+
_build_top_parser().print_help()
113+
return 2
114+
115+
target, _ = COMMANDS[command]
116+
forwarded = argv[1:]
117+
118+
# If user typed: openmmdl <command> --help, it will be forwarded
119+
# and the underlying argparse will handle it.
120+
prog = f"openmmdl {command}"
121+
try:
122+
return _run_target(target, forwarded, prog=prog)
123+
except SystemExit as e:
124+
# Preserve argparse exit behavior from downstream CLIs
125+
return int(e.code) if isinstance(e.code, int) else 0
126+
127+
128+
if __name__ == "__main__":
129+
raise SystemExit(main())

0 commit comments

Comments
 (0)