Skip to content

Commit fd1faae

Browse files
alxndrkalininedyoshikunclaude
authored
modularizing data package (#366)
* add planning roadmap * docs: start milestone v1.1 Extract viscy-data * docs: complete viscy-data project research * docs: define milestone v1.1 requirements * docs: create milestone v1.1 roadmap (4 phases) * docs(06-package-scaffolding-and-foundation): create phase plan * feat(06-01): create viscy-data package directory structure with pyproject.toml - Add pyproject.toml with hatchling build, uv-dynamic-versioning, all base deps - Declare optional dependency groups: triplet, livecell, mmap, all - Add PEP 561 py.typed marker and tests/__init__.py - Configure pattern-prefix for independent versioning Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(06-01): add type definitions and package init with re-exports - Copy all type definitions from viscy/data/typing.py into _typing.py - Add INDEX_COLUMNS from viscy/data/triplet.py for shared access - Update typing_extensions.NotRequired to typing.NotRequired (Python >=3.11) - Create __init__.py with full re-export of all public types - Add README.md required by hatchling build Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(06-01): integrate viscy-data as workspace dependency in root pyproject.toml - Add viscy-data to root dependencies list - Register viscy-data as workspace source in [tool.uv.sources] - Verified editable install and full import chain works Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(06-01): complete package scaffolding plan with summary and state update - Add 06-01-SUMMARY.md documenting viscy-data package creation - Update STATE.md with plan position, metrics, and decisions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(06-02): extract shared utility functions into _utils.py - Extract _ensure_channel_list, _search_int_in_str, _collate_samples, _read_norm_meta from hcs.py - Extract _scatter_channels, _gather_channels, _transform_channel_wise from triplet.py - Update imports to use viscy_data._typing instead of viscy.data.typing - Add __all__ listing all 7 utility functions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(06-02): complete utility module extraction plan - Add 06-02-SUMMARY.md documenting utility extraction - Update STATE.md: Phase 6 complete, progress 80% Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(phase-6): complete phase execution * docs(07-code-migration): create phase plan * feat(07-01): migrate select.py, distributed.py, segmentation.py to viscy-data - Copy select.py with well/FOV filtering utilities (no internal viscy imports) - Copy distributed.py with ShardedDistributedSampler (no internal viscy imports) - Copy segmentation.py with viscy.data.typing -> viscy_data._typing import update - Add missing docstrings to satisfy ruff D rules Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(07-01): migrate hcs.py to viscy-data with utility import rewiring - Copy HCSDataModule, SlidingWindowDataset, MaskTestDataset from main - Replace viscy.data.typing imports with viscy_data._typing - Remove 4 utility function definitions (now in _utils.py) - Add import from viscy_data._utils for shared utilities - Remove unused re and collate_meta_tensor imports - Add missing docstrings for ruff D compliance Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(07-01): migrate gpu_aug.py to viscy-data with dependency rewiring - Copy GPUTransformDataModule, CachedOmeZarrDataset, CachedOmeZarrDataModule - Rewire viscy.data.distributed -> viscy_data.distributed - Rewire viscy.data.hcs utility imports -> viscy_data._utils - Rewire viscy.data.select -> viscy_data.select - Rewire viscy.data.typing -> viscy_data._typing - Add missing docstrings for ruff D compliance Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(07-01): complete core data module migration plan - Add 07-01-SUMMARY.md documenting migration of 5 core modules - Update STATE.md: phase 7 plan 1 of 4, decisions, metrics Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(07-03): migrate mmap_cache.py and ctmc_v1.py to viscy-data - Rewire all imports from viscy.data to viscy_data prefix - Add lazy import for tensordict with clear error message - Add docstrings for ruff D compliance Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(07-03): migrate livecell.py with lazy optional dependency imports - Rewire imports from viscy.data to viscy_data prefix - Add lazy imports for pycocotools, tifffile, torchvision - Add import guards in LiveCellDataset and LiveCellTestDataset __init__ - Add docstrings for ruff D compliance Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(07-03): migrate combined.py as-is with import rewiring - Rewire viscy.data.distributed to viscy_data.distributed - Rewire viscy.data.hcs._collate_samples to viscy_data._utils._collate_samples - Preserve all 6 public classes without structural changes - Add docstrings for ruff D compliance Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(07-02): migrate cell_classification.py and cell_division_triplet.py - Rewire imports from viscy.data to viscy_data prefix - Add lazy import for pandas in cell_classification.py with clear error message - Import _transform_channel_wise from viscy_data._utils (not triplet.py) - Import INDEX_COLUMNS and AnnotationColumns from viscy_data._typing - Add docstrings for ruff D compliance * docs(07-03): complete optional dependency module migration plan Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(07-02): complete specialized module migration plan - Add 07-02-SUMMARY.md documenting triplet, classification, and cell division module migration - Update STATE.md with position, decisions, and metrics Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(07-04): add complete public API exports to viscy_data __init__.py - Export all 45 public names (17 types, 2 utilities, 26 DataModules/Datasets/enums) - Eager imports from all 13 modules (lazy guards handled internally by each module) - Comprehensive __all__ list for IDE autocompletion and star-import support - Ruff-sorted import ordering passes all lint checks Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(07-04): complete public API exports plan - phase 7 fully done - 07-04-SUMMARY.md documenting 45 public exports and full package verification - STATE.md updated: phase 7 complete (4/4 plans), 12 total plans done Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(phase-7): complete code migration execution * docs(08-test-migration-and-validation): create phase plan * test(08-01): add conftest.py with HCS OME-Zarr fixtures for viscy-data - Copy all 6 fixtures and _build_hcs helper from main branch conftest - Replace legacy np.random.rand with np.random.default_rng (NPY002) - No viscy import changes needed (only uses third-party libs) - Provides preprocessed_hcs_dataset, small_hcs_dataset, tracks fixtures Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(08-02): complete smoke tests plan - phase 8 test migration done - Created 08-02-SUMMARY.md documenting 52 smoke tests for viscy_data - Updated STATE.md: phase 8 complete, 14 total plans executed - DATA-TST-02 satisfied: import, __all__, optional dep messages, no legacy namespace Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(08-01): migrate test_hcs, test_triplet, test_select to viscy-data package - Update imports from viscy.data.X to viscy_data - Add BatchedCenterSpatialCropd to _utils.py (fixes batch dim handling) - Fix triplet.py to use BatchedCenterSpatialCropd instead of CenterSpatialCropd - Add tensorstore to test dependency group for triplet tests - All 19 tests pass across 3 test files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(08-01): complete data test migration plan summary - Create 08-01-SUMMARY.md documenting test migration and bug fixes - Update STATE.md with BatchedCenterSpatialCropd decision revision Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(phase-8): complete test migration and validation * docs(09-ci-integration): create phase plan * feat(09-01): add viscy-data CI test jobs to GitHub Actions workflow - Add test-data job with 3x3 matrix (3 OS x 3 Python) for viscy-data - Add test-data-extras job (ubuntu-latest, Python 3.13) for extras validation - Update check job needs to aggregate all test jobs: test, test-data, test-data-extras Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(09-01): complete CI integration plan - Add 09-01-SUMMARY.md documenting viscy-data CI jobs - Update STATE.md: phase 9 complete, v1.0 milestone complete Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(phase-9): complete CI integration - milestone v1.1 done * chore: complete v1.1 milestone — Extract viscy-data Delivered: viscy-data package with 15 modules, 45 public exports, optional dependency groups, 71 tests, and tiered CI. Archives: - milestones/v1.1-ROADMAP.md - milestones/v1.1-REQUIREMENTS.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add missing pandas guards, restore conftest fixture, remove no-op CI filter - Add `if pd is None` guard in ClassificationDataModule.setup() and TripletDataModule._align_tracks_tables_with_positions() to raise helpful ImportError instead of AttributeError when pandas is absent - Fix ClassificationDataset error message to suggest `pip install pandas` instead of `pip install 'viscy-data[triplet]'` (classification doesn't need tensorstore) - Restore `num_timepoints` parameter on `_build_hcs()` and add `temporal_hcs_dataset` fixture from upstream commit 44b25b9 - Remove no-op `-m "not slow"` from test-data-extras CI job (no tests use @pytest.mark.slow) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: add CLAUDE.md and update CONTRIBUTING.md Add CLAUDE.md with project-specific instructions for Claude Code sessions. Update CONTRIBUTING.md with ruff config centralization warning and numpy docstring convention note. Synced from 71009b5. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: update uv.lock after rebase onto modular-viscy-staging Regenerate lockfile to include viscy-data workspace dependencies alongside viscy-models from the updated base branch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * port changes from tests-zarrv3 branch * ruff * add additional test for the main dataloaders * redundant tets 3. I think test 2 alreaady takes care of this. * rename INDEX_COLUMNS * remove unused LABEL classes * fix(livecell): assign transform result and avoid mutable defaults LiveCellTestDataset.__getitem__ discarded the return value of self.transform(sample), so MONAI transforms had no effect. Also replace mutable default lists in LiveCellDataModule.__init__ with None to prevent cross-instance state sharing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cell_classification): raise ValueError, tighten val_fovs type, fix mutable default - `raise (f"Unknown stage: {stage}")` raised a string instead of an exception — use `ValueError`. - `val_fovs: list[str] | None` was unconditionally indexed in `setup()` — remove the `None` option since it's always required. - `_subset(..., exclude_timepoints=[])` used a mutable default — replace with `None`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(gpu_aug): remove _filter_fit_fovs override so exclude_fovs is applied CachedOmeZarrDataModule accepted exclude_fovs but its local _filter_fit_fovs override only filtered wells, silently ignoring excluded FOVs. Remove the override so the SelectWell mixin's implementation (which filters both wells and FOVs) is used. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: rename select.py to _select.py (private module) The module contains mostly private helpers (_filter_wells, _filter_fovs) and a mixin dataclass (SelectWell). Renaming to _select.py signals it is internal implementation detail. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: update package descriptions to "AI x Imaging" and CLAUDE.md Update viscy-data description from "virtual staining microscopy" to "AI x Imaging tasks" in README, pyproject.toml, and __init__.py. Add viscy-models test example to CLAUDE.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ctmc_v1): add missing prefetch_factor attribute CTMCv1DataModule.__init__ did not set self.prefetch_factor, causing an AttributeError when train_dataloader() or val_dataloader() was called (inherited from GPUTransformDataModule). Set it to None. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add functional tests for ctmc, livecell, segmentation, classification Add unit tests for the four data modules that previously only had import smoke tests: - test_ctmc_v1.py: setup, val subsample ratio, batch shape - test_livecell.py: dataset/datamodule with mock TIFF + COCO data - test_segmentation.py: paired pred/target datasets, z-slice - test_cell_classification.py: annotation CSV, FOV split, timepoint exclusion Also adds shared fixtures to conftest.py (single_channel_hcs_pair, segmentation_hcs_pair, classification_hcs_dataset). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(livecell): add missing prefetch_factor; add dataloader iteration tests Add prefetch_factor attribute to LiveCellDataModule (same fix as 97455eb for CTMC). Add batch iteration + shape validation to classification and livecell datamodule tests to match coverage patterns in test_hcs/test_triplet. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: delete leftover select.py after rename to _select.py Commit 5b132f9 renamed select.py to _select.py but did not remove the original file. Nothing imports from it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use explicit positions[0] instead of leaked loop variable CachedOmeZarrDataset and MmappedDataset both built self.channels using the loop variable `position` after iterating, implicitly depending on the last element. Use positions[0] to be explicit and avoid UnboundLocalError on empty input. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(livecell): handle empty annotations and correct return type Guard torch.stack against empty annotation lists in LiveCellTestDataset.__getitem__ when load_labels=True, returning properly shaped empty tensors instead of crashing. Fix _parse_image_names return type annotation: list[Path] -> list[str]. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(segmentation): defer open_ome_zarr from __init__ to setup() Store only paths in __init__ and open OME-Zarr stores in setup("test"), consistent with other DataModules in the package and Lightning conventions for resource lifecycle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * print to logger * refactor(triplet): remove BatchedCenterSpatialCropd from viscy-data The transform already exists in viscy-transforms and viscy-data should not depend on it. Replace the final crop with a shape validation check in on_after_batch_transfer() and require initial_yx_patch_size to match the desired output size. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(docs): convert Sphinx-style docstrings to numpy style in _utils.py Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(init): lazy-load submodules via PEP 562 __getattr__ Replace eager imports of all DataModule/Dataset submodules with on-demand loading. Modules with optional dependencies (triplet, livecell, mmap_cache) are no longer imported at `import viscy_data` time. Add __init__.pyi stub for type-checker/IDE support. Also split CI test-data job to run without --all-extras so the base package is validated independently from optional dependencies. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: guard None dereferences and replace mutable default arguments - cell_classification.py: guard _read_norm_meta() returning None - hcs.py: guard MaskTestDataset with ground_truth_masks=None, add missing array_key parameter, replace mutable default [] with None - triplet.py, cell_division_triplet.py: replace mutable default [] with None for normalizations/augmentations parameters Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: correct return type annotations in _utils.py _gather_channels and _transform_channel_wise return Tensor, not list[Tensor]. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(combined): check stage before calling dm.setup() Move the unsupported-stage guard to the top of setup() in ConcatDataModule and CachedConcatDataModule so constituent data modules are not set up for stages that will be rejected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add tests for cell_division_triplet, mmap_cache, and HCS test stage - test_cell_division_triplet.py: 11 smoke tests for dataset and datamodule - test_mmap_cache.py: 5 smoke tests (skipped when tensordict missing) - test_hcs.py: add setup("test") coverage for MaskTestDataset Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Eduardo Hirata-Miyasaki <edhiratam@gmail.com> Co-authored-by: Alexandr Kalinin <alxndrkalinin@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4ac3050 commit fd1faae

70 files changed

Lines changed: 13570 additions & 1682 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test.yml

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,61 @@ jobs:
4040
run: uv run --frozen pytest --cov=src/ --cov-report=term-missing
4141
working-directory: packages/${{ matrix.package }}
4242

43+
test-data:
44+
name: Test Data (Python ${{ matrix.python-version }}, ${{ matrix.os }})
45+
runs-on: ${{ matrix.os }}
46+
strategy:
47+
fail-fast: true
48+
matrix:
49+
os: [ubuntu-latest, macos-latest, windows-latest]
50+
python-version: ["3.11", "3.12", "3.13"]
51+
52+
steps:
53+
- name: Checkout repository
54+
uses: actions/checkout@v5
55+
56+
- name: Set up uv with Python ${{ matrix.python-version }}
57+
uses: astral-sh/setup-uv@v7
58+
with:
59+
python-version: ${{ matrix.python-version }}
60+
enable-cache: true
61+
cache-suffix: ${{ matrix.os }}-${{ matrix.python-version }}
62+
63+
- name: Install dependencies
64+
run: uv sync --frozen --dev
65+
working-directory: packages/viscy-data
66+
67+
- name: Run tests with coverage
68+
run: uv run --frozen pytest --cov=viscy_data --cov-report=term-missing
69+
working-directory: packages/viscy-data
70+
71+
test-data-extras:
72+
name: Test Data Extras (Python 3.13, ubuntu-latest)
73+
runs-on: ubuntu-latest
74+
75+
steps:
76+
- name: Checkout repository
77+
uses: actions/checkout@v5
78+
79+
- name: Set up uv with Python 3.13
80+
uses: astral-sh/setup-uv@v7
81+
with:
82+
python-version: "3.13"
83+
enable-cache: true
84+
cache-suffix: ubuntu-latest-3.13
85+
86+
- name: Install dependencies
87+
run: uv sync --frozen --all-extras --dev
88+
working-directory: packages/viscy-data
89+
90+
- name: Run tests with coverage
91+
run: uv run --frozen pytest --cov=viscy_data --cov-report=term-missing
92+
working-directory: packages/viscy-data
93+
4394
check:
4495
name: All tests pass
4596
if: always()
46-
needs: [test]
97+
needs: [test, test-data, test-data-extras]
4798
runs-on: ubuntu-latest
4899
steps:
49100
- name: Verify all test jobs succeeded

.planning/MILESTONES.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
# Milestones: VisCy Modularization
22

3+
## v1.1 — Extract viscy-data
4+
5+
**Shipped:** 2026-02-14
6+
**Phases:** 6–9 (4 executed)
7+
8+
**What shipped:**
9+
- `viscy-data` package extracted with src layout (15 modules, 4015 LOC)
10+
- 45 public exports with clean import paths: `from viscy_data import X`
11+
- Optional dependency groups: `[triplet]`, `[livecell]`, `[mmap]`, `[all]`
12+
- Shared utilities extracted from hcs.py into _utils.py
13+
- All existing data tests passing (71 tests)
14+
- Tiered CI for viscy-data (3x3 base + 1x1 extras)
15+
16+
---
17+
318
## v1.0 — Transforms & Monorepo Skeleton
419

520
**Shipped:** 2026-01-29

.planning/PROJECT.md

Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,83 +2,67 @@
22

33
## What This Is
44

5-
Restructuring VisCy from a monolithic package into a uv workspace monorepo. This enables reusing transforms, dataloaders, and models in downstream projects without requiring the entire VisCy package as a dependency. The second milestone extracts `viscy-models` as an independent package containing all 8 network architectures as pure nn.Modules, organized by function (unet/, vae/, contrastive/) with shared components factored into a `components/` module.
5+
Restructuring VisCy from a monolithic package into a uv workspace monorepo. This enables reusing transforms, dataloaders, and models in downstream projects without requiring the entire VisCy package as a dependency. Two subpackages are now extracted: `viscy-transforms` (v1.0) and `viscy-data` (v1.1).
66

77
## Core Value
88

9-
**Independent, reusable subpackages with clean import paths.** Users can `pip install viscy-models` and use `from viscy_models import UNeXt2` without pulling in the entire VisCy ecosystem.
10-
11-
## Current Milestone: v1.1 Models
12-
13-
**Goal:** Extract all network architectures into `viscy-models` as pure nn.Modules with comprehensive test coverage.
14-
15-
**Target features:**
16-
- `viscy-models` package with 8 architectures organized by function (unet/, vae/, contrastive/)
17-
- Shared components extracted to `components/` (stems, heads, decoder blocks)
18-
- Full test coverage: migrate existing + write new for UNeXt2, ContrastiveEncoder, BetaVAE
19-
- Independent of viscy-transforms and lightning (torch/timm/monai deps only)
20-
- State dict key compatibility preserved for checkpoint loading
9+
**Independent, reusable subpackages with clean import paths.** Users can `pip install viscy-transforms` or `pip install viscy-data` and use clean imports without pulling in the entire VisCy ecosystem.
2110

2211
## Requirements
2312

2413
### Validated
2514

26-
- ✓ uv workspace scaffolding with `packages/` directory structure — v1.0
27-
-`viscy-transforms` package extracted with src layout — v1.0
28-
- ✓ Import path: `from viscy_transforms import X` (clean break) — v1.0
29-
- ✓ hatchling build backend with uv-dynamic-versioning — v1.0
30-
- ✓ All existing transform tests passing in new structure — v1.0
31-
- ✓ CI updated for monorepo structure — v1.0
15+
- uv workspace scaffolding with `packages/` directory structure — v1.0
16+
- `viscy-transforms` package extracted with src layout — v1.0
17+
- Import path: `from viscy_transforms import X` (clean break) — v1.0
18+
- hatchling build backend with uv-dynamic-versioning — v1.0
19+
- All existing transform tests passing in new structure — v1.0
20+
- CI for monorepo (9-job test matrix + lint) — v1.0
21+
- `viscy-data` package extracted with src layout (15 modules, 4015 LOC) — v1.1
22+
- All 13 data modules migrated with clean import paths — v1.1
23+
- Import path: `from viscy_data import X` (45 public exports) — v1.1
24+
- No dependency on viscy-transforms (BatchedCenterSpatialCropd in _utils.py) — v1.1
25+
- Optional dependency groups: `[triplet]`, `[livecell]`, `[mmap]`, `[all]` — v1.1
26+
- Shared utilities extracted from hcs.py into _utils.py — v1.1
27+
- All existing data tests passing (71 tests) — v1.1
28+
- Tiered CI for viscy-data (3x3 base + 1x1 extras) — v1.1
3229

3330
### Active
3431

35-
- [ ] `viscy-models` package with src layout and function-based organization
36-
- [ ] All 8 architectures migrated: UNeXt2, FCMAE, ContrastiveEncoder, ResNet3dEncoder, BetaVae25D, BetaVaeMonai, Unet2d, Unet25d
37-
- [ ] Shared components extracted to `components/` (stems, heads, blocks)
38-
- [ ] Full test coverage: existing tests migrated + new tests for untested models
39-
- [ ] Import path: `from viscy_models import UNeXt2` (clean break)
40-
- [ ] State dict key compatibility preserved
41-
- [ ] CI includes viscy-models in test matrix
32+
(None — next milestone not yet defined)
4233

4334
### Out of Scope
4435

45-
- Hydra/BaseModel registry infrastructure — deferred to future `viscy-hydra` package
46-
- BaseModelMeta metaclass — deferred to future `viscy-hydra` package
47-
- Extracting data packages (viscy-data) — future milestone
48-
- Application-level LightningModules — move to applications/ in future milestone
36+
- Extracting viscy-models, viscy-airtable — future milestones
37+
- Meta-package with re-exports — decided against, clean break approach
4938
- Backward-compatible imports — not maintaining
50-
- Documentation (Zensical + GitHub Pages) — deferred from v1.0
39+
- Zensical documentation / GitHub Pages — deferred
40+
- Hydra integration — per design doc
41+
- GPU transform unification (GPUTransformMixin) — future refactor
5142

5243
## Context
5344

5445
**Design doc:** https://github.com/mehta-lab/VisCy/issues/353
5546

56-
**Reference implementations:**
57-
- flowbench BaseModel: `/home/eduardo.hirata/repos/flowbench/src/models/base_model.py` (future reference for viscy-hydra)
58-
- lightning-hydra-template: https://github.com/ashleve/lightning-hydra-template (future reference)
59-
- iohub pyproject.toml: modern hatchling + uv-dynamic-versioning pattern
60-
61-
**Current state (post v1.0):**
62-
- uv workspace with `viscy-transforms` at `packages/viscy-transforms/`
63-
- Root `viscy` umbrella package with dynamic versioning
64-
- Models in monolithic `viscy/unet/networks/` and `viscy/representation/`
65-
- 14+ shared components in unext2.py used by fcmae, contrastive, vae
66-
- No tests for UNeXt2, ContrastiveEncoder, or BetaVAE
47+
**Current state (after v1.1):**
48+
- uv workspace monorepo with 2 extracted packages:
49+
- `packages/viscy-transforms/` — 16 transform modules, 44 exports
50+
- `packages/viscy-data/` — 15 data modules, 45 exports, 4015 LOC source + 671 LOC tests
51+
- CI: test.yml (viscy-transforms 3x3, viscy-data 3x3 + extras 1x1) + lint.yml
52+
- Python >=3.11, hatchling + uv-dynamic-versioning
53+
- Original code on `main` branch for reference
6754

68-
**Architecture vision:**
69-
- `viscy-models`: Pure nn.Module architectures (this milestone)
70-
- `viscy-hydra`: BaseModel, BaseModelMeta, Hydra config utilities (future milestone)
71-
- Applications (Cytoland, DynaCLR): LightningModules composing models with training logic (future milestone)
55+
**Architecture reference:**
56+
- `viscy/data/README.md` documents module inventory, class hierarchy, training pipeline mapping, GPU transform patterns
7257

7358
## Constraints
7459

75-
- **Package naming**: `viscy-models` (hyphen) as package name, `viscy_models` (underscore) as import
76-
- **Python version**: >=3.11 (matching current VisCy)
77-
- **Build system**: hatchling with uv-dynamic-versioning (following viscy-transforms pattern)
78-
- **Layout**: src layout required (`packages/viscy-models/src/viscy_models/`)
79-
- **Independence**: viscy-models must NOT depend on viscy-transforms or lightning
80-
- **Dependencies**: torch, timm, monai, numpy only
81-
- **Tooling**: uv only, no pip/setuptools for package management
60+
- **Package naming**: hyphen for package name, underscore for import
61+
- **Python version**: >=3.11
62+
- **Build system**: hatchling with uv-dynamic-versioning
63+
- **Layout**: src layout (`packages/*/src/*/`)
64+
- **Tooling**: uv only
65+
- **No cross-package dependencies between data and transforms**
8266

8367
## Key Decisions
8468

@@ -88,10 +72,13 @@ Restructuring VisCy from a monolithic package into a uv workspace monorepo. This
8872
| hatchling over setuptools | Modern, faster, better uv integration | ✓ Good |
8973
| src layout | Prevents import confusion during development | ✓ Good |
9074
| Tests inside packages | Isolated testing, `uv run --package` workflow | ✓ Good |
91-
| Pure nn.Module in viscy-models | No Lightning/Hydra coupling; maximum reusability | — Pending |
92-
| Hydra infra in separate package | Keeps model package lightweight; Hydra optional for consumers | — Pending |
93-
| Function-based grouping (unet/, vae/, contrastive/) | Clean organization for 8+ models with shared components | — Pending |
94-
| viscy-models independent of viscy-transforms | Keep packages loosely coupled | — Pending |
75+
| No viscy-transforms dep in data | Transforms separate from data | ✓ Good |
76+
| Optional dependency groups | Heavy deps as extras, lean base install | ✓ Good |
77+
| Extract shared utils from hcs.py | Prevent dual-role module anti-pattern | ✓ Good |
78+
| BatchedCenterSpatialCropd in _utils.py | CenterSpatialCropd can't handle batch dim in on_after_batch_transfer | ✓ Good |
79+
| Lazy imports for optional deps | try/except at module level, guard in __init__ | ✓ Good |
80+
| Flat public API (45 exports) | MONAI pattern, consistent with viscy-transforms | ✓ Good |
81+
| combined.py preserved as-is | No split per REF-02 deferral | ✓ Good |
9582

9683
---
97-
*Last updated: 2026-02-12 after requirements definition*
84+
*Last updated: 2026-02-14 after v1.1 milestone completion*

0 commit comments

Comments
 (0)