| name | dependency-deprecation |
| description | Pattern for deprecating external dependencies while maintaining backward compatibility. Trigger: removing Java/FIJI/MATLAB, deprecating optional deps |
| author | KINTSUGI Team |
| date | Thu Dec 11 2025 00:00:00 GMT+0000 (Coordinated Universal Time) |
Dependency Deprecation Pattern
Experiment Overview
| Item | Details |
|---|---|
| Date | 2025-12-11 |
| Goal | Remove Java/Maven/FIJI/CLIJ2 dependencies from KINTSUGI while maintaining backward compatibility |
| Environment | Python 3.10+, cross-platform (Windows/Linux/macOS) |
| Status | Success |
Context
KINTSUGI originally depended on Java/Maven for PyImageJ and CLIJ2 GPU processing. This created installation friction and cross-platform issues. The goal was to replace these with pure Python implementations (CuPy/NumPy) while allowing legacy users to continue using Java if needed.
Verified Workflow
Step 1: Identify all dependency touchpoints
Search for all references to the dependency:
# Search code
grep -r "java\|Java\|FIJI\|fiji\|clij\|CLIJ\|maven\|Maven\|ImageJ\|imagej" src/ notebooks/
# Check configuration files
grep -r "java\|openjdk\|maven" envs/ pyproject.toml
Files typically affected:
pyproject.toml- optional dependenciesenvs/*.yml- conda environment filessrc/*/deps.py- dependency checkerdocs/*.md- documentation- Core modules using the dependency
Step 2: Update the core module with deprecation
# Example: edf.py - deprecating CLIJ2 backend
import warnings
from typing import Literal
BackendType = Literal["auto", "cupy", "numpy", "clij2"]
def _detect_backend(self, requested: BackendType) -> str:
"""Detect best available backend."""
if requested == "clij2":
warnings.warn(
"CLIJ2 backend is deprecated and will be removed in v2.0. "
"Use 'cupy' or 'numpy' instead.",
DeprecationWarning,
stacklevel=2
)
# Still allow it to work for now
if self._check_clij2_available():
return "clij2"
else:
warnings.warn("CLIJ2 not available, falling back to cupy")
requested = "auto"
if requested == "auto":
# NEW priority order: CuPy > NumPy (CLIJ2 excluded from auto)
if self._check_cupy_available():
return "cupy"
return "numpy"
return requested
Step 3: Update dependency checker
# deps.py - mark as deprecated but keep functional
def _check_java(self, verbose: bool):
"""Check Java installation.
.. deprecated::
Java/Maven dependencies are no longer required for core functionality.
Kept for backward compatibility with legacy CLIJ2 workflows.
"""
if verbose:
print("\n[Java/Maven] (DEPRECATED - no longer required)")
# Still check and report, but don't fail
try:
# ... existing check code ...
if verbose:
print(f" [OK] java v{version} (optional)")
except Exception as e:
if verbose:
print(f" [SKIP] java (optional, not required)")
Step 4: Update pyproject.toml
[project.optional-dependencies]
# Keep the optional group but exclude from [full]
java = [
"JPype1>=1.5.0",
"scyjava>=1.0.0",
"pyimagej>=1.4.0",
]
# Remove java from full install
full = [
"kintsugi[gpu,viz,dl,analysis,bio]", # Note: java excluded
]
Step 5: Update environment files
# envs/env-*.yml - comment out with deprecation note
# Java/ImageJ Integration (DEPRECATED - no longer required)
# Uncomment if you need legacy CLIJ2 support:
# - openjdk=11
# - maven
# - jpype1
Step 6: Update documentation
Add deprecation notices to all relevant docs:
> **Note:** Java, Maven, and FIJI are no longer required. KINTSUGI now uses
> pure Python implementations (CuPy/NumPy) for all processing including EDF.
For historical documents, add a header:
> **DEPRECATION NOTICE (2025):** This document is historical. Java/Maven/FIJI
> dependencies have been removed. See `src/kintsugi/edf.py` for current implementation.
Failed Attempts (Critical)
| Attempt | Why it Failed | Lesson Learned |
|---|---|---|
| Removing code completely | Broke existing user workflows | Keep deprecated code functional |
| Silent removal | Users confused when code stopped working | Always emit deprecation warnings |
| Keeping in [full] install | Users still got Java install failures | Exclude from aggregate installs |
| No migration path | Users didn't know what to use instead | Document the replacement clearly |
Key Insights
- Gradual deprecation: Mark as deprecated first, remove in next major version
- Keep it working: Deprecated doesn't mean broken - users need time to migrate
- Clear warnings: Use Python's
warnings.warn()withDeprecationWarning - Document the alternative: Every deprecation notice should say what to use instead
- Update ALL touchpoints: Code, configs, docs, environment files, README
- Test both paths: Verify deprecated code still works AND new code works
Checklist for Dependency Deprecation
- Search entire codebase for dependency references
- Add deprecation warnings to code using the dependency
- Update auto-detection to prefer new implementation
- Keep optional dependency group but exclude from
[full] - Comment out in environment files with explanation
- Update installation documentation
- Add deprecation notices to historical docs
- Update CLAUDE.md / project documentation
- Test deprecated path still works
- Test new path works
- Update changelog/release notes
References
- Python deprecation warnings: https://docs.python.org/3/library/warnings.html
- Semantic versioning for breaking changes: https://semver.org/
- PEP 387 - Backwards Compatibility Policy: https://peps.python.org/pep-0387/