This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Aydin is a self-supervised, auto-tuned image denoising tool for n-dimensional images. It provides four interfaces: GUI (Aydin Studio), napari plugin, CLI, and Python API. Supports classical denoisers, patch-based methods, and machine learning approaches (CNN, Gradient Boosting).
pip install -e ".[dev]"
# Or use the Makefile (also installs docs deps + pre-commit hooks):
make setup# Run all tests (excludes heavy, gpu, unstable by default)
make test
# Run a single test file
pytest src/aydin/path/to/test_file.py --disable-pytest-warnings
# Run a single test function
pytest src/aydin/path/to/test_file.py::test_function_name --disable-pytest-warnings
# Run heavy tests only (marked @pytest.mark.heavy)
make test-heavy
# Run GPU tests only (marked @pytest.mark.gpu)
make test-gpu# Format code (isort + black)
make format
# Check formatting and lint
make checkaydin # Launch GUI (Aydin Studio)
aydin denoise image.tif # CLI denoising
aydin -h # Helpmake docs # Build HTML docs (current version)
make docs-build # Build multi-version docs (all tags)
make docs-publish # Build and deploy to GitHub PagesUses a src/ layout: source code lives in src/aydin/. This prevents accidental imports of the uninstalled package from the repo root.
Image Translator Framework (src/aydin/it/):
base.py- CoreImageTranslatorBaseclass that handles multi-dimensional arrays with batch/channel/spatial dimensions, training/inference slicing, transforms, and normalizationclassic.py,cnn_torch.py,fgr.py- Implementations wrapping different denoising approaches
Denoising Algorithms (src/aydin/restoration/denoise/):
classic.py- Classical denoisers (Butterworth, Gaussian, NLM, Total Variation)noise2selffgr.py- Self-supervised Feature Generation & Regression (recommended approach)noise2selfcnn.py- Self-supervised CNN approach
Regression Methods (src/aydin/regression/):
cb.py- CatBoost (default for FGR)lgbm.py- LightGBM- Other: linear, perceptron, random forest, SVM
Feature Engineering (src/aydin/features/):
standard_features.py,extensible_features.py- Feature generation for ML denoisers
Transforms (src/aydin/it/transforms/):
- Image preprocessing/postprocessing: deskew, motion correction, high-pass, range normalization, histogram stretching, VST, padding
I/O (src/aydin/io/):
io.py- Image reading/writing supporting TIFF, CZI, ND2, Zarr formats
Interfaces:
src/aydin/gui/- PyQt6-based GUI (Aydin Studio)src/aydin/cli/cli.py- Click-based CLI
- Build backend: hatchling (configured in
pyproject.toml) - Version: Single source of truth is
src/aydin/__init__.py(__version__).pyproject.tomlreads it dynamically via[tool.hatch.version]. - Makefile: Orchestrates common commands (
make helpfor full list)make setup/make install-dev- Install for developmentmake test/make test-heavy/make test-gpu- Run testsmake format/make check- Code formatting and lintingmake validate- Pre-publish checks (format + lint + clean tree)make build/make clean- Build and clean artifactsmake publish/make publish-patch- Create release PR (see Release Process below)
Tests use pytest markers defined in pyproject.toml:
@pytest.mark.heavy- Long-running tests@pytest.mark.gpu- Requires NVIDIA GPU@pytest.mark.unstable- Flaky tests
Use the internal logging API at src/aydin/util/log/log.py instead of print statements.
The project uses calendar versioning: YYYY.M.D (e.g., 2025.2.4), with an optional .patch suffix for same-day releases (e.g., 2025.2.4.1).
- Single source of truth:
src/aydin/__init__.py→__version__ = "YYYY.M.D" pyproject.tomlreads it dynamically via[tool.hatch.version]— never edit the version theredocs/source/conf.pyalso reads from__init__.pyat build time
Releases go through a PR-based flow. Requires the GitHub CLI (gh).
# Regular release (bumps to today's date, e.g., 2025.2.16)
make publish
# Patch release (e.g., 2025.2.16.1 → 2025.2.16.2)
make publish-patchWhat make publish does:
- Runs
make validate(checks: on main, clean tree, formatting, lint) - Creates a
release/vYYYY.M.Dbranch - Bumps
__version__insrc/aydin/__init__.py - Pushes and creates a PR via
gh pr create - Switches back to
main
After that, you merge the PR on GitHub. Then the automated pipeline takes over:
PR merged → release.yml creates git tag → publish.yml: verify → test → build → PyPI → GitHub Release
Workflows (.github/workflows/):
| Workflow | Trigger | Purpose |
|---|---|---|
test_pull_requests.yml |
PR to main |
Style, lint, tests across Python 3.9–3.13, Linux/macOS/Windows |
release.yml |
Release PR merged | Auto-creates git tag, calls publish.yml |
publish.yml |
Tag push / workflow_call / manual | Verify tag, test, build, publish to PyPI, create GitHub Release |
labeler.yml |
PR opened | Auto-labels PRs by changed paths |
link_check.yml |
PR to main |
Checks Markdown links |
Why release.yml calls publish.yml directly: Git tags pushed by GITHUB_TOKEN don't trigger other workflows (GitHub security restriction). So release.yml uses workflow_call to invoke publish.yml directly instead of relying on the tag push event. The push: tags trigger on publish.yml remains as a fallback for manual tag pushes. A workflow_dispatch trigger is also available for manual retries from the GitHub UI.
PyPI authentication: Uses OIDC trusted publishing (no API tokens). The publish-to-pypi job runs in the pypi environment with id-token: write permission.
- Config file:
.flake8(repo root) — single source of truth for flake8 settings - Used by: Makefile (
make lint), CI lint job, and pre-commit hook - Per-file
E501ignores are set for GUI files with HTML-containing docstrings
- Follow PEP8 + Black formatter (config in pyproject.toml, single quotes preserved)
- Use NumPy-style docstrings
- Flake8 config in
.flake8(ignores E203, E741, W503, and others; per-file E501 for GUI docstrings)
The Aydin GUI (Aydin Studio) renders Python docstrings as HTML using Qt's RichText. Docstrings in certain modules contain intentional HTML markup that MUST be preserved. Removing or converting these tags breaks the GUI display.
-
<a href="...">text</a>- Clickable hyperlinks rendered in the GUI. Found in:src/aydin/it/classic_denoisers/*.py- Wikipedia links for algorithm names (Butterworth, NLM, Wavelet, Lipschitz, Bilateral, BM3D/ND, Harmonic, TV)src/aydin/it/transforms/highpass.py- Wikipedia link for 'blue' noisesrc/aydin/restoration/denoise/noise2self*.py- arXiv link to Noise2Self papersrc/aydin/regression/cb.py,lgbm.py,random_forest.py- GitHub links to librariessrc/aydin/gui/tabs/qt/summary.py- DOI, GitHub, and forum links
-
<moreless>- Custom tag that creates an expandable "Read more/Read less" UI section. Used in GUI tab class docstrings:src/aydin/gui/tabs/qt/denoise.pysrc/aydin/gui/tabs/qt/processing.pysrc/aydin/gui/tabs/qt/dimensions.pysrc/aydin/gui/tabs/qt/summary.pysrc/aydin/gui/tabs/qt/base_cropping.py
-
<split>- Used with<moreless>to create a two-column layout in the expanded section. -
<br>/<br><br>- HTML line breaks. Also, literal\n\nin docstrings is converted to<br><br>at runtime by the restoration modules. -
\n\n(literal backslash-n) - Used as explicit paragraph break markers in classic denoiser docstrings. The GUI code converts these to<br><br>via.replace("\n\n", "<br><br>"). -
<notgui>- Marks the boundary between GUI-visible content and API-only content. Everything before this tag is shown in the GUI; everything after (Parameters, Attributes, etc.) is only visible viahelp(), Sphinx, and IDEs. Stripped at runtime bystrip_notgui()insrc/aydin/util/string/break_text.py. Used in:src/aydin/it/classic_denoisers/*.py- Indenoise_*function docstrings, beforeParameterssrc/aydin/it/transforms/*.py- In transform class docstringssrc/aydin/regression/*.py- In regressor class docstringssrc/aydin/nn/models/*.py- In model class docstringssrc/aydin/features/standard_features.py,extensible_features.py- In feature generator class docstringssrc/aydin/it/classic.py,src/aydin/restoration/denoise/noise2self*.py- In denoiser class docstrings
- Classic denoisers:
src/aydin/restoration/denoise/classic.pyreadsdenoise_*.__doc__, appliesstrip_notgui(), and converts\n\nto<br><br> - FGR regressors:
src/aydin/restoration/denoise/noise2selffgr.pyreads regressor class__doc__, appliesstrip_notgui(), and converts\n\nto<br><br> - CNN models:
src/aydin/restoration/denoise/noise2selfcnn.pyreads model class__doc__, appliesstrip_notgui(), and converts\n\nto<br><br> - Transforms:
src/aydin/gui/_qt/transforms_tab_item.pyreads transform class__doc__, appliesstrip_notgui(), and converts\nto<br> - Tab descriptions:
QReadMoreLessLabelwidget parses<moreless>and<split>markers
- NEVER remove
<a href>links from docstrings in the modules listed above - NEVER remove
<moreless>,<split>,<br>, or<notgui>tags from GUI tab docstrings - NEVER convert HTML links to RST/Markdown format - the GUI needs raw HTML
- Preserve literal
\n\nparagraph markers in classic denoiser docstrings - When improving docstrings, keep the HTML tags intact and only modify the surrounding text
- Use
<notgui>to separate GUI-visible content from API-only sections (Attributes, Parameters, etc.). Place<notgui>on its own line before any section you want hidden from the GUI