From 42fa9d9eb8a99256d876639d1ad819300cd489ec Mon Sep 17 00:00:00 2001 From: Hanjin Liu Date: Sat, 24 Aug 2024 00:33:17 +0900 Subject: [PATCH 1/2] fix some cli --- cylindra/cli/config.py | 1 + cylindra/cli/run.py | 6 +++++- pyproject.toml | 2 +- tests/test_gui_0.py | 37 +++++++++++++++++++++++++++++++++---- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/cylindra/cli/config.py b/cylindra/cli/config.py index 6b1731ac..0c03e988 100644 --- a/cylindra/cli/config.py +++ b/cylindra/cli/config.py @@ -64,6 +64,7 @@ def __call__(self, parser, namespace, values, option_string=None): with open(save_path, mode="w") as f: json.dump(cfg.asdict(), f, indent=4, separators=(", ", ": ")) print(f"Config file imported: {save_path.as_posix()}") + parser.exit() class ParserConfig(ParserBase): diff --git a/cylindra/cli/run.py b/cylindra/cli/run.py index 9196676b..6a8f8f40 100644 --- a/cylindra/cli/run.py +++ b/cylindra/cli/run.py @@ -11,7 +11,7 @@ class ParserRun(ParserBase): cylindra run [bold green]path[/bold green] [bold cyan]options[/bold cyan] [u bold green]path[/u bold green] - Path to the project/image file. + Path to the project/python file. [u bold cyan]options[/u bold cyan] [bold]--headless[/bold] @@ -33,17 +33,21 @@ def run_action( from runpy import run_path ui = start(viewer=self.viewer, headless=headless) + project_path = None if Path(path).suffix in ("", ".tar", ".zip", ".json"): prj = read_project(path) with prj.open_project() as d: py_path = str(prj._script_py_path(d)) out_globs = run_path(py_path, {"ui": ui}) is_project = True + project_path = prj.project_path else: out_globs = run_path(path, {"ui": ui}) is_project = False if callable(main := out_globs.get("main")): main(ui) # script.py style + if project_path is not None: + ui._project_dir = project_path if output is None: if is_project: ui.overwrite_project() diff --git a/pyproject.toml b/pyproject.toml index b3cc47fe..46658e61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,7 @@ dependencies = [ "qt-command-palette>=0.0.7", "matplotlib>=3.8.1", "rich>=13.6.0", - "dask>=2023.12.1", + "dask>=2023.12.1,!=2024.8.1", ] authors = [ { email = "liuha@med.kobe-u.ac.jp" }, diff --git a/tests/test_gui_0.py b/tests/test_gui_0.py index 66fba9c1..717b243d 100644 --- a/tests/test_gui_0.py +++ b/tests/test_gui_0.py @@ -1307,30 +1307,59 @@ def run_cli(*args): ) # fmt: skip run_cli("cylindra", "open", Path(dirpath) / "test-project") run_cli("cylindra", "config", "--list") + run_cli("cylindra", "config", PROJECT_DIR_13PF) + run_cli("cylindra", "config", PROJECT_DIR_14PF / "script.py", "--remove") run_cli("cylindra", "config", PROJECT_DIR_14PF, "--remove") run_cli("cylindra", "workflow", "--list") with tempfile.TemporaryDirectory() as dirpath: + dirpath = Path(dirpath) run_cli( "cylindra", "average", TEST_DIR / "test_project_*", "--molecules", "Mole-*", "--size", "10.0", - "--output", Path(dirpath) / "test.tif", + "--output", dirpath / "test.tif", "--filter", "col('nth') % 2 == 0", "--split", "--seed", "123", ) # fmt: skip + run_cli("cylindra", "run", PROJECT_DIR_14PF, "--headless") + run_cli( + "cylindra", + "run", + PROJECT_DIR_14PF, + "--headless", + "-o", + dirpath / "a.tar", + ) + run_cli("cylindra", "find", "**/*.zip") run_cli("cylindra", "find", "**/*.zip", "--called", "register_path") + code = "import numpy as np\ndef main(ui):\n print(ui.default_config)\n" + + with tempfile.TemporaryDirectory() as tempdir, _config.patch_workflow_path(tempdir): + Path(tempdir).joinpath("test-cli.py").write_text(code) + run_cli("cylindra", "workflow") + run_cli("cylindra", "workflow", "test-cli.py") + + with tempfile.TemporaryDirectory() as tempdir, _config.patch_config_dir(tempdir): + from cylindra.components.spline._config import SplineConfig + + d = Path(tempdir) / "temp" + d.mkdir() + config_path = d / "temp-config.json" + SplineConfig().to_file(config_path) + run_cli("cylindra", "config", config_path, "--import") + for widget in ACTIVE_WIDGETS: widget.close() ACTIVE_WIDGETS.clear() use_app().process_events() - run_cli("cylindra plugin list") - monkeypatch.setattr("builtins.input", lambda _: "") + run_cli("cylindra", "plugin", "list") + monkeypatch.setattr("builtins.input", lambda *_: "") with tempfile.TemporaryDirectory() as dirpath: - run_cli(f"cylindra plugin new {dirpath}") + run_cli("cylindra", "plugin", "new", dirpath) def test_function_menu(make_napari_viewer): From da10acf4807239dc6d2e5e3cbdb75f0c861d9002 Mon Sep 17 00:00:00 2001 From: Hanjin Liu Date: Sat, 24 Aug 2024 10:36:27 +0900 Subject: [PATCH 2/2] make separate file --- cylindra_builtins/_pytest_fixtures.py | 27 +++++++ tests/test_gui_0.py | 106 +----------------------- tests/test_gui_2_cli.py | 111 ++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 105 deletions(-) create mode 100644 tests/test_gui_2_cli.py diff --git a/cylindra_builtins/_pytest_fixtures.py b/cylindra_builtins/_pytest_fixtures.py index 68504399..55000300 100644 --- a/cylindra_builtins/_pytest_fixtures.py +++ b/cylindra_builtins/_pytest_fixtures.py @@ -1,3 +1,4 @@ +import sys from contextlib import suppress import pytest @@ -33,3 +34,29 @@ def ui(make_napari_viewer, request: "pytest.FixtureRequest"): sv.close() StaParameters._viewer = None viewer.close() + + +@pytest.fixture +def run_cli(make_napari_viewer, monkeypatch): + from magicclass.utils import thread_worker + from magicgui.application import use_app + + from cylindra.__main__ import main + from cylindra.cli import set_testing + from cylindra.core import ACTIVE_WIDGETS + + viewer = make_napari_viewer() + set_testing(True) + monkeypatch.setattr("builtins.input", lambda *_: "") + + def _run_cli(*args): + sys.argv = [str(a) for a in args] + main(viewer, ignore_sys_exit=True) + + with thread_worker.blocking_mode(): + yield _run_cli + + for widget in ACTIVE_WIDGETS: + widget.close() + ACTIVE_WIDGETS.clear() + use_app().process_events() diff --git a/tests/test_gui_0.py b/tests/test_gui_0.py index 717b243d..013524f9 100644 --- a/tests/test_gui_0.py +++ b/tests/test_gui_0.py @@ -18,9 +18,7 @@ from cylindra import _config, cylmeasure, view_project from cylindra._config import get_config -from cylindra.const import ( - MoleculesHeader as Mole, -) +from cylindra.const import MoleculesHeader as Mole from cylindra.const import PropertyNames as H from cylindra.widgets import CylindraMainWidget from cylindra.widgets.sta import MaskChoice, TemplateChoice @@ -1260,108 +1258,6 @@ def test_spline_fitter(ui: CylindraMainWidget): ui.macro.redo() -def test_cli(make_napari_viewer, monkeypatch): - import sys - - from cylindra.__main__ import main - from cylindra.cli import set_testing - from cylindra.core import ACTIVE_WIDGETS - - viewer: napari.Viewer = make_napari_viewer() - set_testing(True) - - def run_cli(*args): - sys.argv = [str(a) for a in args] - main(viewer, ignore_sys_exit=True) - - # test help - for cmd in [ - "average", - "config", - "find", - "new", - "open", - "plugin", - "preview", - "run", - "workflow", - ]: - run_cli("cylindra", cmd, "--help") - with thread_worker.blocking_mode(): - run_cli("cylindra") - run_cli("cylindra", "preview", PROJECT_DIR_14PF / "project.json") - run_cli("cylindra", "preview", PROJECT_DIR_14PF / "project.json", "--gui") - run_cli("cylindra", "preview", PROJECT_DIR_14PF / "test_tar.tar") - run_cli("cylindra", "preview", PROJECT_DIR_14PF / "test_zip.zip") - run_cli("cylindra", "preview", PROJECT_DIR_14PF / "test_tar.tar::project.json") - run_cli("cylindra", "preview", PROJECT_DIR_14PF / "test_tar.tar::Mole-0.csv") - - with tempfile.TemporaryDirectory() as dirpath: - run_cli( - "cylindra", "new", - Path(dirpath) / "test-project", - "--image", TEST_DIR / "14pf_MT.tif", - "--multiscales", "1", "2", - "--missing_wedge", "-60", "50", - "--molecules", PROJECT_DIR_14PF / "Mole-*", - ) # fmt: skip - run_cli("cylindra", "open", Path(dirpath) / "test-project") - run_cli("cylindra", "config", "--list") - run_cli("cylindra", "config", PROJECT_DIR_13PF) - run_cli("cylindra", "config", PROJECT_DIR_14PF / "script.py", "--remove") - run_cli("cylindra", "config", PROJECT_DIR_14PF, "--remove") - run_cli("cylindra", "workflow", "--list") - with tempfile.TemporaryDirectory() as dirpath: - dirpath = Path(dirpath) - run_cli( - "cylindra", "average", - TEST_DIR / "test_project_*", - "--molecules", "Mole-*", - "--size", "10.0", - "--output", dirpath / "test.tif", - "--filter", "col('nth') % 2 == 0", - "--split", "--seed", "123", - ) # fmt: skip - run_cli("cylindra", "run", PROJECT_DIR_14PF, "--headless") - run_cli( - "cylindra", - "run", - PROJECT_DIR_14PF, - "--headless", - "-o", - dirpath / "a.tar", - ) - - run_cli("cylindra", "find", "**/*.zip") - run_cli("cylindra", "find", "**/*.zip", "--called", "register_path") - - code = "import numpy as np\ndef main(ui):\n print(ui.default_config)\n" - - with tempfile.TemporaryDirectory() as tempdir, _config.patch_workflow_path(tempdir): - Path(tempdir).joinpath("test-cli.py").write_text(code) - run_cli("cylindra", "workflow") - run_cli("cylindra", "workflow", "test-cli.py") - - with tempfile.TemporaryDirectory() as tempdir, _config.patch_config_dir(tempdir): - from cylindra.components.spline._config import SplineConfig - - d = Path(tempdir) / "temp" - d.mkdir() - config_path = d / "temp-config.json" - SplineConfig().to_file(config_path) - run_cli("cylindra", "config", config_path, "--import") - - for widget in ACTIVE_WIDGETS: - widget.close() - ACTIVE_WIDGETS.clear() - use_app().process_events() - - run_cli("cylindra", "plugin", "list") - monkeypatch.setattr("builtins.input", lambda *_: "") - with tempfile.TemporaryDirectory() as dirpath: - run_cli("cylindra", "plugin", "new", dirpath) - - def test_function_menu(make_napari_viewer): from cylindra.widgets.subwidgets import Volume diff --git a/tests/test_gui_2_cli.py b/tests/test_gui_2_cli.py new file mode 100644 index 00000000..b387b348 --- /dev/null +++ b/tests/test_gui_2_cli.py @@ -0,0 +1,111 @@ +import tempfile +from pathlib import Path + +from cylindra import _config + +from ._const import PROJECT_DIR_13PF, PROJECT_DIR_14PF, TEST_DIR + + +def test_help(run_cli): + # test help + for cmd in [ + "average", + "config", + "find", + "new", + "open", + "plugin", + "preview", + "run", + "workflow", + ]: + run_cli("cylindra", cmd, "--help") + + +def test_start_gui(run_cli): + run_cli("cylindra") + + +def test_preview(run_cli): + run_cli("cylindra", "preview", PROJECT_DIR_14PF / "project.json") + run_cli("cylindra", "preview", PROJECT_DIR_14PF / "project.json", "--gui") + run_cli("cylindra", "preview", PROJECT_DIR_14PF / "test_tar.tar") + run_cli("cylindra", "preview", PROJECT_DIR_14PF / "test_zip.zip") + run_cli("cylindra", "preview", PROJECT_DIR_14PF / "test_tar.tar::project.json") + run_cli("cylindra", "preview", PROJECT_DIR_14PF / "test_tar.tar::Mole-0.csv") + + +def test_new_and_open(run_cli): + with tempfile.TemporaryDirectory() as dirpath: + run_cli( + "cylindra", "new", + Path(dirpath) / "test-project", + "--image", TEST_DIR / "14pf_MT.tif", + "--multiscales", "1", "2", + "--missing_wedge", "-60", "50", + "--molecules", PROJECT_DIR_14PF / "Mole-*", + ) # fmt: skip + run_cli("cylindra", "open", Path(dirpath) / "test-project") + + +def test_config(run_cli): + run_cli("cylindra", "config", "--list") + run_cli("cylindra", "config", PROJECT_DIR_13PF) + run_cli("cylindra", "config", PROJECT_DIR_14PF / "script.py", "--remove") + run_cli("cylindra", "config", PROJECT_DIR_14PF, "--remove") + + with tempfile.TemporaryDirectory() as tempdir, _config.patch_config_dir(tempdir): + from cylindra.components.spline._config import SplineConfig + + d = Path(tempdir) / "temp" + d.mkdir() + config_path = d / "temp-config.json" + SplineConfig().to_file(config_path) + run_cli("cylindra", "config", config_path, "--import") + + +def test_average(run_cli): + with tempfile.TemporaryDirectory() as dirpath: + dirpath = Path(dirpath) + run_cli( + "cylindra", "average", + TEST_DIR / "test_project_*", + "--molecules", "Mole-*", + "--size", "10.0", + "--output", dirpath / "test.tif", + "--filter", "col('nth') % 2 == 0", + "--split", "--seed", "123", + ) # fmt: skip + + +def test_run(run_cli): + run_cli("cylindra", "run", PROJECT_DIR_14PF, "--headless") + run_cli( + "cylindra", + "run", + PROJECT_DIR_14PF, + "--headless", + "-o", + Path("test.tar"), + ) + + +def test_find(run_cli): + run_cli("cylindra", "find", "**/*.zip") + run_cli("cylindra", "find", "**/*.zip", "--called", "register_path") + + +def test_workflow(run_cli): + code = "import numpy as np\ndef main(ui):\n print(ui.default_config)\n" + + with tempfile.TemporaryDirectory() as tempdir, _config.patch_workflow_path(tempdir): + Path(tempdir).joinpath("test-cli.py").write_text(code) + run_cli("cylindra", "workflow") + run_cli("cylindra", "workflow", "test-cli.py") + run_cli("cylindra", "workflow", "--list") + + +def test_plugin(run_cli): + run_cli("cylindra", "plugin", "list") + with tempfile.TemporaryDirectory() as dirpath: + run_cli("cylindra", "plugin", "new", dirpath)