diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 00000000..95450e58 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,61 @@ +name: pre-commit (PR only on changed files) + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + detect_changes: + runs-on: ubuntu-latest + outputs: + changed: ${{ steps.changed_files.outputs.changed }} + + steps: + - name: Checkout full history + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Detect changed files + id: changed_files + run: | + git fetch origin ${{ github.base_ref }} + CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD) + + { + echo "changed<> "$GITHUB_OUTPUT" + + - name: Show changed files + run: | + echo "Changed files:" + echo "${{ steps.changed_files.outputs.changed }}" + + precommit: + needs: detect_changes + runs-on: ubuntu-latest + if: ${{ needs.detect_changes.outputs.changed != '' }} + + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ github.head_ref }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install pre-commit + run: pip install pre-commit + + - name: Run pre-commit (CI check-only stage) on changed files + env: + CHANGED_FILES: ${{ needs.detect_changes.outputs.changed }} + run: | + mapfile -t files <<< "$CHANGED_FILES" + pre-commit run --hook-stage manual --files "${files[@]}" --show-diff-on-failure diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 77f27c91..533cb137 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,21 +2,28 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: - - id: check-docstring-first + - id: check-added-large-files + - id: check-yaml + - id: check-toml - id: end-of-file-fixer + - id: name-tests-test - id: trailing-whitespace - - repo: https://github.com/asottile/setup-cfg-fmt - rev: v3.2.0 - hooks: - - id: setup-cfg-fmt - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.10 + rev: v0.15.4 hooks: # Run the formatter. - id: ruff-format # Run the linter. - id: ruff-check args: [--fix,--unsafe-fixes] + - repo: https://github.com/tox-dev/pyproject-fmt + rev: v2.16.2 + hooks: + - id: pyproject-fmt + - repo: https://github.com/abravalheri/validate-pyproject + rev: v0.25 + hooks: + - id: validate-pyproject - repo: https://github.com/tlambert03/napari-plugin-checks rev: v0.3.0 hooks: diff --git a/pyproject.toml b/pyproject.toml index 594660f9..9f3a7f13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,19 +1,99 @@ [build-system] -requires = ["setuptools", "wheel", "setuptools_scm"] build-backend = "setuptools.build_meta" +requires = [ "setuptools>=77", "setuptools-scm[toml]>=7", "wheel" ] -[tool.ruff] -lint.select = ["E", "F", "B", "I", "UP"] -lint.ignore = ["E741"] -target-version = "py310" -fix = true -line-length = 120 +[project] +name = "napari-deeplabcut" +description = "napari + DeepLabCut annotation tool" +readme = { file = "README.md", content-type = "text/markdown" } +license = "LGPL-3.0-only" +license-files = [ "LICENSE" ] +requires-python = ">=3.10" +classifiers = [ + "Development Status :: 2 - Pre-Alpha", + "Framework :: napari", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "Topic :: Scientific/Engineering :: Image Processing", + "Topic :: Scientific/Engineering :: Visualization", +] +# Using setuptools-scm -> version is derived from git tags +dynamic = [ "version" ] +dependencies = [ + "dask-image", + "matplotlib>=3.3", + "napari==0.6.6", + "natsort", + "numpy>=1.18.5,<2", + "opencv-python-headless", + "pandas", + "pyside6>=6.4.2", + "pyyaml", + "qtpy>=2.4", + "scikit-image", + "scipy", + "tables", +] +[[project.authors]] +name = "Team DeepLabCut, led by Jessy Lauer" +email = "admin@deeplabcut.org" +[project.entry-points."napari.manifest"] +napari-deeplabcut = "napari_deeplabcut:napari.yaml" +[project.optional-dependencies] +testing = [ + "pillow", + "pytest", + "pytest-cov", + "pytest-qt", + "tox", +] +[project.urls] +"Bug Tracker" = "https://github.com/DeepLabCut/napari-deeplabcut/issues" +Documentation = "https://github.com/DeepLabCut/napari-deeplabcut#README.md" +"Source Code" = "https://github.com/DeepLabCut/napari-deeplabcut" +"User Support" = "https://github.com/DeepLabCut/napari-deeplabcut/issues" -[tool.uv] -package = true +# ---------------------------- +# setuptools configuration +# ---------------------------- +[tool.setuptools] +include-package-data = true +[tool.setuptools.package-data] +napari_deeplabcut = [ "napari.yaml" ] +[tool.setuptools.package-dir] +"" = "src" +[tool.setuptools.packages.find] +where = [ "src" ] [tool.setuptools_scm] write_to = "src/napari_deeplabcut/_version.py" +[tool.uv] +package = true + +# ---------------------------- +# existing tool configuration +# ---------------------------- +[tool.ruff] +target-version = "py310" +line-length = 120 +fix = true +[tool.ruff.lint] +select = [ "E", "F", "B", "I", "UP" ] +ignore = [ "E741" ] +[tool.ruff.lint.pydocstyle] +convention = "google" + +[tool.pyproject-fmt] +max_supported_python = "3.12" +generate_python_version_classifiers = true +# Avoid collapsing tables to field.key = value format (less readable) +table_format = "long" + [tool.pytest.ini_options] qt_api = "pyside6" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index fe16cb09..00000000 --- a/setup.cfg +++ /dev/null @@ -1,67 +0,0 @@ -[metadata] -name = napari-deeplabcut -description = napari + DeepLabCut annotation tool -long_description = file: README.md -long_description_content_type = text/markdown -url = https://github.com/DeepLabCut/napari-deeplabcut -author = Team DeepLabCut, Lead by Jessy Lauer -author_email = admin@deeplabcut.org -license = LGPL-3.0 -license_files = LICENSE -classifiers = - Development Status :: 2 - Pre-Alpha - Framework :: napari - Intended Audience :: Developers - Operating System :: OS Independent - Programming Language :: Python :: 3 - Programming Language :: Python :: 3 :: Only - Topic :: Scientific/Engineering :: Artificial Intelligence - Topic :: Scientific/Engineering :: Image Processing - Topic :: Scientific/Engineering :: Visualization -project_urls = - Bug Tracker = https://github.com/DeepLabCut/napari-deeplabcut/issues - Documentation = https://github.com/DeepLabCut/napari-deeplabcut#README.md - Source Code = https://github.com/DeepLabCut/napari-deeplabcut - User Support = https://github.com/DeepLabCut/napari-deeplabcut/issues - -[options] -packages = find: -install_requires = - dask-image - matplotlib>=3.3 - napari==0.6.6 - natsort - numpy>=1.18.5,<2.0.0 - opencv-python-headless - pandas - pyside6>=6.4.2 - pyyaml - qtpy>=2.4 - scikit-image - scipy - tables -python_requires = >=3.10 -include_package_data = True -package_dir = - =src -setup_requires = - setuptools-scm - -[options.packages.find] -where = src - -[options.entry_points] -napari.manifest = - napari-deeplabcut = napari_deeplabcut:napari.yaml - -[options.extras_require] -testing = - Pillow - pytest - pytest-cov - pytest-qt - tox - -[options.package_data] -napari_deeplabcut = - napari.yaml diff --git a/src/napari_deeplabcut/__init__.py b/src/napari_deeplabcut/__init__.py index 6f92c484..0c5dbf49 100644 --- a/src/napari_deeplabcut/__init__.py +++ b/src/napari_deeplabcut/__init__.py @@ -40,7 +40,8 @@ # FIXME: Circumvent the need to access window.qt_viewer warnings.filterwarnings("ignore", category=FutureWarning) -import re +import re # noqa: E402 + # Suppress RuntimeWarnings caused by NaN values in dataframe # (encountered during model-predicted labels refinement stage) warnings.filterwarnings( @@ -49,6 +50,7 @@ message=re.escape("invalid value encountered in cast"), ) + class VispyWarningFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: ignore_messages = ( diff --git a/src/napari_deeplabcut/_tests/test_reader.py b/src/napari_deeplabcut/_tests/test_reader.py index c21a87be..1efc73ad 100644 --- a/src/napari_deeplabcut/_tests/test_reader.py +++ b/src/napari_deeplabcut/_tests/test_reader.py @@ -374,7 +374,7 @@ def test_lazy_imread_grayscale_and_rgba(tmp_path): gray = (np.random.rand(10, 10) * 255).astype(np.uint8) rgba = (np.random.rand(10, 10, 4) * 255).astype(np.uint8) p1, p2 = tmp_path / "g.png", tmp_path / "r.png" - cv2.imwrite(str(p1), gray) # cv2 writes grayscale as-is; color images are written as BGR + cv2.imwrite(str(p1), gray) # cv2 writes grayscale as-is; color images are written as BGR cv2.imwrite(str(p2), cv2.cvtColor(rgba, cv2.COLOR_RGBA2BGRA)) res = _reader._lazy_imread([p1, p2], use_dask=False, stack=False) assert all(img.shape[-1] == 3 for img in res) diff --git a/src/napari_deeplabcut/assets/napari_shortcuts.svg b/src/napari_deeplabcut/assets/napari_shortcuts.svg index da59f60e..89922286 100644 --- a/src/napari_deeplabcut/assets/napari_shortcuts.svg +++ b/src/napari_deeplabcut/assets/napari_shortcuts.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/src/napari_deeplabcut/assets/superanimal_quadruped.json b/src/napari_deeplabcut/assets/superanimal_quadruped.json index 2c6a4689..21e3cdfb 100644 --- a/src/napari_deeplabcut/assets/superanimal_quadruped.json +++ b/src/napari_deeplabcut/assets/superanimal_quadruped.json @@ -155,4 +155,4 @@ 707.5655627887081, 375.0788206592507 ] -} \ No newline at end of file +} diff --git a/src/napari_deeplabcut/assets/superanimal_topviewmouse.json b/src/napari_deeplabcut/assets/superanimal_topviewmouse.json index 0d8f69c6..42495e5a 100644 --- a/src/napari_deeplabcut/assets/superanimal_topviewmouse.json +++ b/src/napari_deeplabcut/assets/superanimal_topviewmouse.json @@ -107,4 +107,4 @@ 117.41024099594408, 252.35239163633167 ] -} \ No newline at end of file +} diff --git a/src/napari_deeplabcut/styles/dark.mplstyle b/src/napari_deeplabcut/styles/dark.mplstyle index 11a8ce6c..1658f9b4 100644 --- a/src/napari_deeplabcut/styles/dark.mplstyle +++ b/src/napari_deeplabcut/styles/dark.mplstyle @@ -9,4 +9,4 @@ axes.labelcolor : f0f1f2 axes.facecolor : none axes.edgecolor : 414851 xtick.color : f0f1f2 -ytick.color : f0f1f2 \ No newline at end of file +ytick.color : f0f1f2 diff --git a/src/napari_deeplabcut/styles/light.mplstyle b/src/napari_deeplabcut/styles/light.mplstyle index 0484b228..3b8d7d1d 100644 --- a/src/napari_deeplabcut/styles/light.mplstyle +++ b/src/napari_deeplabcut/styles/light.mplstyle @@ -9,4 +9,4 @@ axes.labelcolor : 3b3a39 axes.facecolor : none axes.edgecolor : d6d0ce xtick.color : 3b3a39 -ytick.color : 3b3a39 \ No newline at end of file +ytick.color : 3b3a39