diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml index cb581b79..13d86788 100644 --- a/.github/workflows/test_and_deploy.yml +++ b/.github/workflows/test_and_deploy.yml @@ -1,6 +1,3 @@ -# This workflows will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - name: test and deploy on: @@ -8,7 +5,7 @@ on: branches: - main tags: - - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10 + - "v*" pull_request: branches: - main @@ -18,76 +15,109 @@ jobs: test: name: ${{ matrix.platform }} py${{ matrix.python-version }} runs-on: ${{ matrix.platform }} + strategy: + fail-fast: false matrix: -# platform: [ubuntu-latest, windows-latest] # , macos-latest - platform: [ubuntu-latest] - python-version: ['3.8', '3.9'] #issues with monai and 3.10; pausing for now. users should use python 3.9 + platform: [ubuntu-latest, windows-latest, macos-latest] + python-version: ["3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} + cache: pip -# these libraries enable testing on Qt on linux - - uses: tlambert03/setup-qt-libs@v1 + - name: Install Qt libraries on Linux + if: runner.os == 'Linux' + uses: tlambert03/setup-qt-libs@v1 -# strategy borrowed from vispy for installing opengl libs on windows - name: Install Windows OpenGL if: runner.os == 'Windows' + shell: pwsh run: | git clone --depth 1 https://github.com/pyvista/gl-ci-helpers.git - powershell gl-ci-helpers/appveyor/install_opengl.ps1 - if (Test-Path -Path "C:\Windows\system32\opengl32.dll" -PathType Leaf) {Exit 0} else {Exit 1} - -# note: if you need dependencies from conda, considering using -# setup-miniconda: https://github.com/conda-incubator/setup-miniconda -# and -# tox-conda: https://github.com/tox-dev/tox-conda - - name: Install dependencies + ./gl-ci-helpers/appveyor/install_opengl.ps1 + if (Test-Path -Path "C:\Windows\system32\opengl32.dll" -PathType Leaf) { + exit 0 + } else { + exit 1 + } + + - name: Install tox run: | python -m pip install --upgrade pip - python -m pip install setuptools tox tox-gh-actions - python -m pip install tifffile - python -m pip install monai[nibabel,einops,tifffile] -# pip install git+https://github.com/lucasb-eyer/pydensecrf.git@master#egg=pydensecrf - -# this runs the platform-specific tests declared in tox.ini - - name: Test with tox - uses: GabrielBB/xvfb-action@v1 # aganders3/headless-gui@v1 + python -m pip install tox tox-gh-actions + + - name: Test with tox on Linux + if: runner.os == 'Linux' + uses: GabrielBB/xvfb-action@v1 with: run: python -m tox env: PLATFORM: ${{ matrix.platform }} + QT_API: pyqt6 + PYTEST_QT_API: pyqt6 + VISPY_USE_APP: pyqt6 + QT_OPENGL: software + PYVISTA_OFF_SCREEN: true - - name: Coverage - uses: codecov/codecov-action@v2 + - name: Test with tox on Windows/macOS + if: runner.os != 'Linux' + run: python -m tox + env: + PLATFORM: ${{ matrix.platform }} + QT_API: pyqt6 + PYTEST_QT_API: pyqt6 + VISPY_USE_APP: pyqt6 + QT_OPENGL: software + PYVISTA_OFF_SCREEN: true + + - name: Upload coverage + if: matrix.platform == 'ubuntu-latest' && matrix.python-version == '3.12' + uses: codecov/codecov-action@v6 + with: + files: ./coverage.xml + fail_ci_if_error: false + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} deploy: -# this will run when you have tagged a commit, starting with "v*" -# and requires that you have put your twine API key in your -# github secrets (see readme for details) needs: [test] runs-on: ubuntu-latest - if: contains(github.ref, 'tags') + if: startsWith(github.ref, 'refs/tags/v') + steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v6 with: - python-version: "3.x" - - name: Install dependencies + python-version: "3.12" + + - name: Install build tools run: | python -m pip install --upgrade pip - pip install -U setuptools setuptools_scm wheel twine build - - name: Build and publish + python -m pip install build twine + + - name: Build package + run: | + python -m build + + - name: Check package + run: | + python -m twine check dist/* + + - name: Publish to PyPI env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.TWINE_API_KEY }} run: | - git tag - python -m build . twine upload dist/* diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index 2b497c7c..00000000 --- a/.isort.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[settings] -force_single_line = True -force_sort_within_sections = False -lexicographical = True -single_line_exclusions = ('typing',) -order_by_type = False -group_by_package = True -skip=__init__.py diff --git a/napari_cellseg3d/__init__.py b/napari_cellseg3d/__init__.py index 7a1ba361..c53f096d 100644 --- a/napari_cellseg3d/__init__.py +++ b/napari_cellseg3d/__init__.py @@ -1,3 +1,8 @@ """napari-cellseg3d - napari plugin for cell segmentation.""" -__version__ = "0.2.2" +try: + from napari_cellseg3d._version import version as __version__ +except ImportError: + from importlib.metadata import version + + __version__ = version("napari_cellseg3d") diff --git a/napari_cellseg3d/_tests/conftest.py b/napari_cellseg3d/_tests/conftest.py deleted file mode 100644 index bbfeff10..00000000 --- a/napari_cellseg3d/_tests/conftest.py +++ /dev/null @@ -1,18 +0,0 @@ -import os - -import pytest - - -@pytest.fixture(scope="session", autouse=True) -def env_config(): - """ - Configure environment variables needed for the test session - """ - - # This makes QT render everything offscreen and thus prevents - # any Modals / Dialogs or other Widgets being rendered on the screen while running unit tests - os.environ["QT_QPA_PLATFORM"] = "offscreen" - - yield - - os.environ.pop("QT_QPA_PLATFORM") diff --git a/napari_cellseg3d/_tests/pytest.ini b/napari_cellseg3d/_tests/pytest.ini deleted file mode 100644 index 45c3be1c..00000000 --- a/napari_cellseg3d/_tests/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -qt_api=pyqt5 diff --git a/napari_cellseg3d/_tests/test_base_plugin.py b/napari_cellseg3d/_tests/test_base_plugin.py index ff049657..188a9135 100644 --- a/napari_cellseg3d/_tests/test_base_plugin.py +++ b/napari_cellseg3d/_tests/test_base_plugin.py @@ -1,11 +1,17 @@ from pathlib import Path +from types import SimpleNamespace +import pytest +from qtpy.QtWidgets import QWidget + +from napari_cellseg3d.code_plugins import plugin_base from napari_cellseg3d.code_plugins.plugin_base import ( + BasePluginFolder, BasePluginSingleImage, ) -def test_base_single_image(make_napari_viewer_proxy): +def test_base_single_image_update_default_paths(make_napari_viewer_proxy): viewer = make_napari_viewer_proxy() plugin = BasePluginSingleImage(viewer) @@ -13,7 +19,360 @@ def test_base_single_image(make_napari_viewer_proxy): test_image = str(test_folder / "res/test.tif") assert plugin._check_results_path(str(test_folder)) + plugin.image_path = test_image assert plugin._default_path[0] != test_image + plugin._update_default_paths() - assert plugin._default_path[0] == test_image + + assert plugin._default_path == [test_image, None, None] + + +def test_check_results_path_creates_missing_folder( + make_napari_viewer_proxy, tmp_path +): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + + results_dir = tmp_path / "new" / "results" + + assert not results_dir.exists() + assert plugin._check_results_path(str(results_dir)) + assert results_dir.is_dir() + + +def test_check_results_path_empty_string_returns_false( + make_napari_viewer_proxy, +): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + + assert plugin._check_results_path("") is False + + +def test_check_results_path_rejects_non_string(make_napari_viewer_proxy): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + + with pytest.raises(TypeError, match="Expected string"): + plugin._check_results_path(None) + + +def test_single_image_build_not_implemented(make_napari_viewer_proxy): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + + with pytest.raises( + NotImplementedError, match="To be defined in child classes" + ): + plugin._build() + + +def test_make_navigation_buttons(make_napari_viewer_proxy, qtbot): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + a_wdg = QWidget() + b_wdg = QWidget() + qtbot.addWidget(a_wdg) + qtbot.addWidget(b_wdg) + plugin.addTab(a_wdg, "A") + plugin.addTab(b_wdg, "B") + plugin.setCurrentIndex(1) + + prev_button = plugin._make_prev_button() + next_button = plugin._make_next_button() + + prev_button.click() + assert plugin.currentIndex() == 0 + + next_button.click() + assert plugin.currentIndex() == 1 + + +def test_remove_docked_widgets_success(make_napari_viewer_proxy): + viewer = make_napari_viewer_proxy() + plugin = BasePluginSingleImage(viewer) + + dock = viewer.window.add_dock_widget(plugin, name="temporary dock") + plugin.docked_widgets = [dock] + plugin.container_docked = True + + assert plugin.remove_docked_widgets() is True + assert plugin.docked_widgets == [] + assert plugin.container_docked is False + + +def test_remove_docked_widgets_handles_lookup_error( + make_napari_viewer_proxy, monkeypatch +): + viewer = make_napari_viewer_proxy() + plugin = BasePluginSingleImage(viewer) + + plugin.docked_widgets = [object()] + plugin.container_docked = True + + def raise_lookup_error(_dock_widget): + raise LookupError + + monkeypatch.setattr( + viewer.window, "remove_dock_widget", raise_lookup_error + ) + + assert plugin.remove_docked_widgets() is False + + +def test_extract_dataset_paths_empty(): + assert BasePluginFolder.extract_dataset_paths([]) is None + + +def test_extract_dataset_paths_none(): + assert BasePluginFolder.extract_dataset_paths([None]) is None + + +def test_extract_dataset_paths_returns_parent(tmp_path): + image_path = tmp_path / "images" / "image.tif" + image_path.parent.mkdir() + image_path.write_text("fake") + + assert BasePluginFolder.extract_dataset_paths([str(image_path)]) == str( + image_path.parent + ) + + +def test_folder_update_default_paths_from_existing_paths( + make_napari_viewer_proxy, tmp_path +): + plugin = BasePluginFolder(make_napari_viewer_proxy()) + + image_dir = tmp_path / "images" + label_dir = tmp_path / "labels" + val_dir = tmp_path / "validation" + results_dir = tmp_path / "results" + + for folder in [image_dir, label_dir, val_dir, results_dir]: + folder.mkdir() + + plugin.images_filepaths = [str(image_dir / "img.tif")] + plugin.labels_filepaths = [str(label_dir / "lab.tif")] + plugin.validation_filepaths = [str(val_dir / "val.tif")] + plugin.results_path = str(results_dir) + + plugin._update_default_paths() + + assert plugin._default_path == [ + str(image_dir), + str(label_dir), + str(val_dir), + str(results_dir), + ] + + +def test_folder_update_default_paths_appends_existing_dir( + make_napari_viewer_proxy, + tmp_path, +): + plugin = BasePluginFolder(make_napari_viewer_proxy()) + + plugin._update_default_paths(str(tmp_path)) + + assert str(tmp_path) in plugin._default_path + + +def test_load_dataset_paths(make_napari_viewer_proxy, monkeypatch, tmp_path): + plugin = BasePluginFolder(make_napari_viewer_proxy()) + + image_0 = tmp_path / "0.tif" + image_1 = tmp_path / "1.tif" + image_0.write_text("fake") + image_1.write_text("fake") + + expected = [image_0, image_1] + + monkeypatch.setattr( + plugin_base.ui, + "open_folder_dialog", + lambda *_args, **_kwargs: str(tmp_path), + ) + monkeypatch.setattr( + plugin_base.utils, + "get_all_matching_files", + lambda _directory: expected, + ) + + assert plugin.load_dataset_paths() == expected + + +def test_load_dataset_paths_warns_when_empty( + make_napari_viewer_proxy, + monkeypatch, + tmp_path, +): + plugin = BasePluginFolder(make_napari_viewer_proxy()) + + warnings = [] + + monkeypatch.setattr( + plugin_base.ui, + "open_folder_dialog", + lambda *_args, **_kwargs: str(tmp_path), + ) + monkeypatch.setattr( + plugin_base.utils, + "get_all_matching_files", + lambda _directory: [], + ) + monkeypatch.setattr( + plugin_base.logger, + "warning", + lambda msg: warnings.append(msg), + ) + + assert plugin.load_dataset_paths() == [] + assert warnings + assert "does not contain any compatible" in warnings[0] + + +def test_load_image_dataset(make_napari_viewer_proxy, monkeypatch, tmp_path): + plugin = BasePluginFolder(make_napari_viewer_proxy()) + + image_0 = tmp_path / "b.tif" + image_1 = tmp_path / "a.tif" + image_0.write_text("fake") + image_1.write_text("fake") + + monkeypatch.setattr( + plugin, "load_dataset_paths", lambda: [image_0, image_1] + ) + + plugin.load_image_dataset() + + assert plugin.images_filepaths == [str(image_1), str(image_0)] + assert plugin.image_filewidget.text_field.text() == str(tmp_path) + + +def test_load_label_dataset(make_napari_viewer_proxy, monkeypatch, tmp_path): + plugin = BasePluginFolder(make_napari_viewer_proxy()) + + label_0 = tmp_path / "b.tif" + label_1 = tmp_path / "a.tif" + label_0.write_text("fake") + label_1.write_text("fake") + + monkeypatch.setattr( + plugin, "load_dataset_paths", lambda: [label_0, label_1] + ) + + plugin.load_label_dataset() + + assert plugin.labels_filepaths == [str(label_1), str(label_0)] + assert plugin.labels_filewidget.text_field.text() == str(tmp_path) + + +def test_load_unsup_images_dataset( + make_napari_viewer_proxy, monkeypatch, tmp_path +): + plugin = BasePluginFolder(make_napari_viewer_proxy()) + + image_0 = tmp_path / "b.tif" + image_1 = tmp_path / "a.tif" + image_0.write_text("fake") + image_1.write_text("fake") + + monkeypatch.setattr( + plugin, "load_dataset_paths", lambda: [image_0, image_1] + ) + + plugin.load_unsup_images_dataset() + + assert plugin.validation_filepaths == [str(image_1), str(image_0)] + assert plugin.unsupervised_images_filewidget.text_field.text() == str( + tmp_path + ) + + +def test_show_file_dialog_updates_filetype( + make_napari_viewer_proxy, + monkeypatch, + tmp_path, +): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + + image_path = tmp_path / "image.tif" + image_path.write_text("fake") + + monkeypatch.setattr( + plugin_base.ui, + "open_file_dialog", + lambda *_args, **_kwargs: [str(image_path)], + ) + + result = plugin._show_file_dialog() + + assert result == str(image_path) + assert plugin.filetype == ".tif" + + +def test_show_dialog_images_sets_image_path( + make_napari_viewer_proxy, + monkeypatch, + tmp_path, +): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + + image_path = tmp_path / "image.tif" + image_path.write_text("fake") + + monkeypatch.setattr(plugin, "_show_file_dialog", lambda: str(image_path)) + + plugin._show_dialog_images() + + assert plugin.image_path == str(image_path) + assert plugin.image_filewidget.text_field.text() == str(image_path) + + +def test_show_dialog_labels_sets_label_path( + make_napari_viewer_proxy, + monkeypatch, + tmp_path, +): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + + label_path = tmp_path / "label.tif" + label_path.write_text("fake") + + monkeypatch.setattr(plugin, "_show_file_dialog", lambda: str(label_path)) + + plugin._show_dialog_labels() + + assert plugin.label_path == str(label_path) + assert plugin.labels_filewidget.text_field.text() == str(label_path) + + +def test_load_results_path_sets_results_path( + make_napari_viewer_proxy, + monkeypatch, + tmp_path, +): + plugin = BasePluginSingleImage(make_napari_viewer_proxy()) + + monkeypatch.setattr( + plugin_base.ui, + "open_folder_dialog", + lambda *_args, **_kwargs: str(tmp_path), + ) + + plugin._load_results_path() + + assert plugin.results_path == str(tmp_path.resolve()) + assert plugin.results_filewidget.text_field.text() == str( + tmp_path.resolve() + ) + + +def test_show_and_hide_io_element_without_toggle(qtbot): + widget = QWidget() + widget.setVisible(False) + qtbot.addWidget(widget) + + BasePluginSingleImage._show_io_element(widget) + + assert widget.isVisible() + + BasePluginSingleImage._hide_io_element(widget) + + assert not widget.isVisible() diff --git a/napari_cellseg3d/_tests/test_labels_correction.py b/napari_cellseg3d/_tests/test_labels_correction.py index b4f13238..bd1b0412 100644 --- a/napari_cellseg3d/_tests/test_labels_correction.py +++ b/napari_cellseg3d/_tests/test_labels_correction.py @@ -37,12 +37,14 @@ def test_correct_labels(): ) -def test_relabel(): +def test_relabel(make_napari_viewer_proxy): + viewer = make_napari_viewer_proxy() cl.relabel( str(image_path), str(labels_path), go_fast=True, test=True, + viewer=viewer, ) diff --git a/napari_cellseg3d/_tests/test_weight_download.py b/napari_cellseg3d/_tests/test_weight_download.py index e1392436..6f6a0c48 100644 --- a/napari_cellseg3d/_tests/test_weight_download.py +++ b/napari_cellseg3d/_tests/test_weight_download.py @@ -1,10 +1,17 @@ +import os + +import pytest + from napari_cellseg3d.code_models.workers_utils import ( PRETRAINED_WEIGHTS_DIR, WeightsDownloader, ) -# DISABLED, causes GitHub actions to freeze +@pytest.mark.skipif( + os.getenv("CI") == "true", + reason="This test causes CI to freeze", +) def test_weight_download(): downloader = WeightsDownloader() downloader.download_weights("test", "test.pth") diff --git a/napari_cellseg3d/code_models/worker_inference.py b/napari_cellseg3d/code_models/worker_inference.py index 46ba77eb..65bf0d24 100644 --- a/napari_cellseg3d/code_models/worker_inference.py +++ b/napari_cellseg3d/code_models/worker_inference.py @@ -1,4 +1,5 @@ """Contains the :py:class:`~InferenceWorker` class, which is a custom worker to run inference jobs in.""" + import platform import sys from pathlib import Path @@ -268,7 +269,6 @@ def load_layer(self): f" please check for extra channel/batch dimensions" ) volume = utils.correct_rotation(volume) - # volume = np.reshape(volume, newshape=(1, 1, *volume.shape)) dims_check = volume.shape @@ -280,7 +280,7 @@ def load_layer(self): if self.config.model_info.name != "WNet3D" else lambda x: x ) - volume = np.reshape(volume, newshape=(1, *volume.shape)) + volume = volume.reshape((1, *volume.shape)) if self.config.sliding_window_config.is_enabled(): load_transforms = Compose( [ diff --git a/napari_cellseg3d/dev_scripts/correct_labels.py b/napari_cellseg3d/dev_scripts/correct_labels.py index 572ca429..694c9102 100644 --- a/napari_cellseg3d/dev_scripts/correct_labels.py +++ b/napari_cellseg3d/dev_scripts/correct_labels.py @@ -1,3 +1,5 @@ +"""Tools to correct labels and add missing labels to the label image.""" + import threading import time import warnings @@ -89,7 +91,7 @@ def add_label(old_label, artefact, new_label_path, i_labels_to_add): returns = [] -def ask_labels(unique_artefact, test=False): +def _ask_labels(unique_artefact, test=False): global returns returns = [] if not test: @@ -204,14 +206,15 @@ def relabel( while loop: # visualize the artefact and ask the user which label to add to the label image t = threading.Thread( - target=partial(ask_labels, test=test), args=(unique_artefact,) + target=partial(_ask_labels, test=test), args=(unique_artefact,) ) t.start() artefact_copy = np.where( np.isin(artefact, i_labels_to_add), 0, artefact ) if viewer is None: - viewer = napari.view_image(image) + viewer = napari.Viewer() + viewer.add_image(image, name="image") else: viewer = viewer viewer.add_image(image, name="image") diff --git a/pyproject.toml b/pyproject.toml index 329d119c..d2f79565 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,9 +14,9 @@ classifiers = [ "Topic :: Software Development :: Testing", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Operating System :: OS Independent", "License :: OSI Approved :: MIT License", "Topic :: Scientific/Engineering :: Artificial Intelligence", @@ -24,7 +24,7 @@ classifiers = [ "Topic :: Scientific/Engineering :: Visualization", ] license = {text = "MIT"} -requires-python = ">=3.8" +requires-python = ">=3.10" dependencies = [ "numpy", "napari[all]>=0.4.14", @@ -43,29 +43,38 @@ dependencies = [ # "nibabel", # "pillow", "pyclesperanto", - "tqdm", "matplotlib", "pydensecrf2", ] -dynamic = ["version", "entry-points"] +dynamic = ["version"] [project.urls] Homepage = "https://github.com/AdaptiveMotorControlLab/CellSeg3D" Documentation = "https://adaptivemotorcontrollab.github.io/cellseg3d-docs/res/welcome.html" Issues = "https://github.com/AdaptiveMotorControlLab/CellSeg3D/issues" +[project.entry-points."napari.manifest"] +"napari_cellseg3d" = "napari_cellseg3d:napari.yaml" + [build-system] -requires = ["setuptools", "wheel"] +requires = [ + "setuptools>=64", + "setuptools-scm>=8", + "wheel", +] build-backend = "setuptools.build_meta" [tool.setuptools] include-package-data = true +[tool.setuptools_scm] +version_file = "napari_cellseg3d/_version.py" + [tool.setuptools.packages.find] where = ["."] [tool.setuptools.package-data] -"*" = ["res/*.png", "code_models/models/pretrained/*.json", "*.yaml"] +"*" = ["res/*.png", "code_models/models/pretrained/*.json", "*.yaml", "napari.yaml"] [tool.ruff] select = [ @@ -79,7 +88,6 @@ select = [ "PTH", "RET", "SIM", - "TCH", "NPY", ] # Never enforce `E501` (line length violations) and 'E741' (ambiguous variable names) @@ -116,22 +124,12 @@ exclude = [ [tool.ruff.pydocstyle] convention = "google" -[tool.black] -line-length = 79 - -[tool.isort] -profile = "black" -line_length = 79 - [project.optional-dependencies] -pyqt5 = [ - "pyqt5", -] -pyside2 = [ - "pyside2", -] pyside6 = [ - "pyside6", + "napari[pyside6]", +] +pyqt6 = [ + "napari[pyqt6]", ] onnx-cpu = [ "onnx", @@ -145,11 +143,8 @@ wandb = [ "wandb" ] dev = [ - "isort", - "black", "ruff", "pre-commit", - "tuna", "twine", ] docs = [ @@ -165,3 +160,6 @@ test = [ "onnx", "onnxruntime", ] +crf = [ + "pydensecrf2", +] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 1411411d..00000000 --- a/requirements.txt +++ /dev/null @@ -1,24 +0,0 @@ -black -coverage -imageio-ffmpeg>=0.4.5 -isort -itk -jupyter-book -pytest -pytest-qt -tox -twine -numpy -napari[all]>=0.4.14 -QtPy -opencv-python>=4.5.5 -pre-commit -pyclesperanto>=0.18.3 -matplotlib>=3.4.1 -ruff -tifffile>=2022.2.9 -torch>=1.11 -monai[nibabel,einops,tifffile]>=1.0.1 -pillow -scikit-image>=0.19.2 -vispy>=0.9.6 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 001bca5f..00000000 --- a/setup.cfg +++ /dev/null @@ -1,45 +0,0 @@ -[metadata] -name = napari_cellseg3d -version = 0.2.2 - -[options] -packages = find: -include_package_data = True -python_requires = >=3.8 -package_dir = - =. - -# add your package requirements here -install_requires = - numpy - napari[all]>=0.4.14 - QtPy - opencv-python>=4.5.5 - scikit-image>=0.19.2 - matplotlib>=3.4.1 - tifffile>=2022.2.9 - imageio-ffmpeg>=0.4.5 - torch>=1.11 - monai[nibabel,einops,tifffile]>=1.0.1 - itk - tqdm - nibabel - pyclesperanto - scikit-image - pillow - tqdm - matplotlib - vispy>=0.9.6 - -[options.packages.find] -where = . - -[options.package_data] -napari_cellseg3d = - res/*.png - code_models/models/pretrained/*.json - napari.yaml - -[options.entry_points] -napari.manifest = - napari_cellseg3d = napari_cellseg3d:napari.yaml diff --git a/tox.ini b/tox.ini index a0c9ec27..6f2960ca 100644 --- a/tox.ini +++ b/tox.ini @@ -1,26 +1,25 @@ # For more information about tox, see https://tox.readthedocs.io/en/latest/ [tox] -envlist = py{38,39,310}-{linux} -; envlist = py{38,39,310}-{linux,macos,windows} +envlist = py{310,311,312}-{linux,windows,macos} isolated_build=true [gh-actions] python = - 3.8: py38 - 3.9: py39 3.10: py310 + 3.11: py311 + 3.12: py312 [gh-actions:env] PLATFORM = ubuntu-latest: linux - ; windows-latest: windows - ; macos-latest: macos + windows-latest: windows + macos-latest: macos [testenv] platform = linux: linux - ; windows: win32 - ; macos: darwin + windows: win32 + macos: darwin passenv = CI PYTHONPATH @@ -29,20 +28,10 @@ passenv = XAUTHORITY NUMPY_EXPERIMENTAL_ARRAY_FUNCTION PYVISTA_OFF_SCREEN -deps = - pytest # https://docs.pytest.org/en/latest/contents.html - pytest-cov # https://pytest-cov.readthedocs.io/en/latest/ - napari - PyQt5 - magicgui - pytest-qt - qtpy - git+https://github.com/lucasb-eyer/pydensecrf.git@master#egg=pydensecrf - onnx - onnxruntime - monai[tifffile] -; pyopencl[pocl] -; opencv-python -extras = crf +setenv = + windows: USERNAME = runneradmin + windows: TORCHINDUCTOR_CACHE_DIR = {envtmpdir}/torchinductor + +extras = test,crf,pyqt6 usedevelop = true commands = pytest -v --color=yes --cov=napari_cellseg3d --cov-report=xml