Skip to content

Commit 25edd70

Browse files
committed
added movement launch CLI entrypoint (#345)
1 parent 5fd7b10 commit 25edd70

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

movement/cli_entrypoint.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import argparse
44
import platform
5+
import subprocess
6+
import sys
57

68
import numpy as np
79
import pandas as pd
@@ -41,12 +43,19 @@ def main() -> None:
4143
"""Entrypoint for the CLI."""
4244
parser = argparse.ArgumentParser(prog="movement")
4345
subparsers = parser.add_subparsers(dest="command", title="commands")
46+
4447
# Add 'info' command
4548
info_parser = subparsers.add_parser(
4649
"info", help="output diagnostic information about the environment"
4750
)
4851
info_parser.set_defaults(func=info)
4952

53+
# Add 'launch' command
54+
launch_parser = subparsers.add_parser(
55+
"launch", help="launch the movement plugin in napari"
56+
)
57+
launch_parser.set_defaults(func=launch)
58+
5059
args = parser.parse_args()
5160
if args.command is None:
5261
help_message = parser.format_help()
@@ -68,5 +77,20 @@ def info() -> None:
6877
)
6978

7079

80+
def launch() -> None:
81+
"""Launch the movement plugin in napari."""
82+
try:
83+
# Use sys.executable to ensure the correct Python interpreter is used
84+
subprocess.run(
85+
[sys.executable, "-m", "napari", "-w", "movement"], check=True
86+
)
87+
except subprocess.CalledProcessError as e:
88+
# if subprocess.run() fails with non-zero exit code
89+
print(
90+
"\nAn error occurred while launching the movement plugin "
91+
f"for napari:\n {e}"
92+
)
93+
94+
7195
if __name__ == "__main__": # pragma: no cover
7296
main()

tests/test_unit/test_cli_entrypoint.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import subprocess
2+
import sys
13
from contextlib import nullcontext as does_not_raise
24
from unittest.mock import patch
35

@@ -21,6 +23,7 @@
2123
],
2224
)
2325
def test_entrypoint_command(command, expected_exception):
26+
"""Test the entrypoint with different commands: 'info', 'invalid', ''."""
2427
with (
2528
patch("sys.argv", command),
2629
patch("builtins.print") as mock_print,
@@ -29,3 +32,30 @@ def test_entrypoint_command(command, expected_exception):
2932
main()
3033
printed_message = " ".join(map(str, mock_print.call_args.args))
3134
assert e in printed_message
35+
36+
37+
@pytest.mark.parametrize(
38+
"run_side_effect, expected_message",
39+
[
40+
(None, ""), # No error
41+
(subprocess.CalledProcessError(1, "napari"), "error occurred while"),
42+
],
43+
)
44+
def test_launch_command(run_side_effect, expected_message, capsys):
45+
"""Test the 'launch' command.
46+
47+
We mock the subprocess.run function to avoid actually launching napari.
48+
"""
49+
with (
50+
patch("sys.argv", ["movement", "launch"]),
51+
patch("subprocess.run", side_effect=run_side_effect) as mock_run,
52+
):
53+
main()
54+
# Assert that subprocess.run was called with the correct arguments
55+
mock_run.assert_called_once()
56+
args = mock_run.call_args[0][0]
57+
assert args[0] == sys.executable
58+
assert args[1:] == ["-m", "napari", "-w", "movement"]
59+
# Assert that the expected message was printed
60+
captured = capsys.readouterr()
61+
assert expected_message in captured.out

0 commit comments

Comments
 (0)