File size: 8,240 Bytes
4780d8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14c1ba6
 
4780d8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
.PHONY: help install install-dev test test-coverage test-verbose lint format clean docker-build docker-run docker-push docker-clean run-ui run-cli

# Default target
.DEFAULT_GOAL := help

# Variables
DOCKER_IMAGE_NAME := mosaic
DOCKER_TAG := latest
DOCKER_REGISTRY := # Set your registry here (e.g., docker.io/username)
PYTHON := uv run python
PYTEST := uv run pytest
BLACK := uv run black
PYLINT := uv run pylint

##@ General

help: ## Display this help message
	@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf "  \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

##@ Development Setup

install: ## Install production dependencies using uv
	uv sync --no-dev

install-dev: ## Install development dependencies using uv
	uv sync

##@ Testing

test: ## Run all tests
	$(PYTEST) tests/ -v

test-fast: ## Run tests without coverage (faster)
	$(PYTEST) tests/ -v --no-cov

test-coverage: ## Run tests with detailed coverage report
	$(PYTEST) tests/ -v --cov=src/mosaic --cov-report=term-missing --cov-report=html

test-ui: ## Run only UI tests
	$(PYTEST) tests/test_ui_components.py tests/test_ui_events.py -v

test-cli: ## Run only CLI tests
	$(PYTEST) tests/test_cli.py -v

test-verbose: ## Run tests with verbose output and show print statements
	$(PYTEST) tests/ -vv -s

test-specific: ## Run specific test (usage: make test-specific TEST=tests/test_cli.py::TestClass::test_method)
	$(PYTEST) $(TEST) -v

test-watch: ## Run tests in watch mode (requires pytest-watch)
	$(PYTEST) tests/ --watch

##@ Code Quality

lint: ## Run linting checks with pylint
	$(PYLINT) src/mosaic/

lint-strict: ## Run pylint on both src and tests
	$(PYLINT) src/mosaic/ tests/

format: ## Format code with black
	$(BLACK) src/ tests/

format-check: ## Check code formatting without making changes
	$(BLACK) --check src/ tests/

quality: format-check lint ## Run all code quality checks

##@ Application

run-ui: ## Launch Gradio web interface
	$(PYTHON) -m mosaic.gradio_app

run-ui-public: ## Launch Gradio web interface with public sharing
	$(PYTHON) -m mosaic.gradio_app --share

run-single: ## Run single slide analysis (usage: make run-single SLIDE=path/to/slide.svs OUTPUT=output_dir)
	$(PYTHON) -m mosaic.gradio_app --slide-path $(SLIDE) --output-dir $(OUTPUT)

run-batch: ## Run batch analysis from CSV (usage: make run-batch CSV=settings.csv OUTPUT=output_dir)
	$(PYTHON) -m mosaic.gradio_app --slide-csv $(CSV) --output-dir $(OUTPUT)

##@ Docker

docker-build: ## Build Docker image
	docker build -t $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) .

docker-build-no-cache: ## Build Docker image without cache
	docker build --no-cache -t $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) .

docker-run: ## Run Docker container (web UI mode)
	docker run -it --rm \
		--gpus all \
		-p 7860:7860 \
		-v $(PWD)/data:/app/data \
		-v $(PWD)/output:/app/output \
		$(DOCKER_IMAGE_NAME):$(DOCKER_TAG)

docker-run-single: ## Run Docker container (single slide mode)
	docker run -it --rm \
		--gpus all \
		-v $(PWD)/data:/app/data \
		-v $(PWD)/output:/app/output \
		$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) \
		--slide-path /app/data/$(SLIDE) \
		--output-dir /app/output

docker-run-batch: ## Run Docker container (batch mode)
	docker run -it --rm \
		--gpus all \
		-v $(PWD)/data:/app/data \
		-v $(PWD)/output:/app/output \
		$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) \
		--slide-csv /app/data/$(CSV) \
		--output-dir /app/output

docker-shell: ## Open shell in Docker container
	docker run -it --rm \
		--gpus all \
		-v $(PWD)/data:/app/data \
		-v $(PWD)/output:/app/output \
		$(DOCKER_IMAGE_NAME):$(DOCKER_TAG) \
		/bin/bash

docker-tag: ## Tag Docker image for registry
	docker tag $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG)

docker-push: docker-tag ## Push Docker image to registry
	docker push $(DOCKER_REGISTRY)/$(DOCKER_IMAGE_NAME):$(DOCKER_TAG)

docker-clean: ## Remove Docker image
	docker rmi $(DOCKER_IMAGE_NAME):$(DOCKER_TAG) || true

docker-prune: ## Clean up Docker build cache
	docker system prune -f
	docker builder prune -f

##@ Cleanup

clean: ## Remove build artifacts and cache files
	find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
	find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true
	find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
	find . -type d -name ".ruff_cache" -exec rm -rf {} + 2>/dev/null || true
	find . -type f -name "*.pyc" -delete
	find . -type f -name "*.pyo" -delete
	find . -type f -name ".coverage" -delete
	rm -rf htmlcov/
	rm -rf dist/
	rm -rf build/

clean-outputs: ## Remove output files (masks, results CSVs)
	rm -rf output/*
	@echo "Output directory cleaned"

clean-all: clean docker-clean ## Remove all build artifacts, cache, and Docker images

##@ Model Management

download-models: ## Download required models from HuggingFace
	@echo "Downloading models from HuggingFace Hub..."
	$(PYTHON) -m mosaic.gradio_app --download-models-only

##@ Documentation

docs-requirements: ## Show what needs to be documented
	@echo "Documentation TODO:"
	@echo "  - API documentation"
	@echo "  - Model architecture details"
	@echo "  - CLI usage examples"
	@echo "  - Docker deployment guide"

##@ CI/CD

ci-test: install-dev test-coverage format-check ## Run all CI checks (no lint to save time)
	@echo "All CI checks passed!"

ci-test-strict: install-dev test-coverage format-check lint ## Run all CI checks including pylint
	@echo "All strict CI checks passed!"

ci-docker: docker-build ## Build Docker image for CI
	@echo "Docker image built successfully"

##@ Development Utilities

shell: ## Open Python shell with project in path
	$(PYTHON)

ipython: ## Open IPython shell with project in path
	uv run ipython

notebook: ## Start Jupyter notebook server
	uv run jupyter notebook

check-deps: ## Check for outdated dependencies
	uv pip list --outdated

update-deps: ## Update dependencies (be careful!)
	uv sync --upgrade

lock: ## Update lock file
	uv lock

##@ Git Hooks

pre-commit-install: ## Install pre-commit hooks
	@echo "Setting up pre-commit hooks..."
	@echo "#!/bin/sh" > .git/hooks/pre-commit
	@echo "make format-check test-fast" >> .git/hooks/pre-commit
	@chmod +x .git/hooks/pre-commit
	@echo "Pre-commit hooks installed (format-check + test-fast)"

pre-commit-uninstall: ## Uninstall pre-commit hooks
	rm -f .git/hooks/pre-commit
	@echo "Pre-commit hooks uninstalled"

##@ Information

info: ## Display project information
	@echo "Mosaic - H&E Whole Slide Image Analysis"
	@echo "========================================"
	@echo ""
	@echo "Python version:"
	@$(PYTHON) --version
	@echo ""
	@echo "UV version:"
	@uv --version
	@echo ""
	@echo "Project structure:"
	@echo "  src/mosaic/          - Main application code"
	@echo "  tests/               - Test suite"
	@echo "  data/                - Input data directory"
	@echo "  output/              - Analysis results"
	@echo ""
	@echo "Key commands:"
	@echo "  make install-dev     - Setup development environment"
	@echo "  make test            - Run test suite"
	@echo "  make run-ui          - Launch web interface"
	@echo "  make docker-build    - Build Docker image"

version: ## Show version information
	@$(PYTHON) -c "import mosaic; print(f'Mosaic version: {mosaic.__version__}')" 2>/dev/null || echo "Version info not available"

tree: ## Show project directory tree (requires tree command)
	@tree -L 3 -I '__pycache__|*.pyc|*.egg-info|.pytest_cache|.ruff_cache|htmlcov|.venv' . || echo "tree command not found. Install with: apt-get install tree"

##@ Performance

profile: ## Profile a single slide analysis (usage: make profile SLIDE=path/to/slide.svs)
	$(PYTHON) -m cProfile -o profile.stats -m mosaic.gradio_app --slide-path $(SLIDE) --output-dir profile_output
	$(PYTHON) -c "import pstats; p = pstats.Stats('profile.stats'); p.sort_stats('cumulative'); p.print_stats(20)"

benchmark: ## Run performance benchmarks
	@echo "Running benchmark suite..."
	@echo "This will process the test slide and measure performance"
	time $(PYTHON) -m mosaic.gradio_app --slide-path tests/testdata/948176.svs --output-dir benchmark_output