This guide covers development setup, testing, and contributing workflows for LayerD.
LayerD uses uv to manage the development environment.
# Install core dependencies + dev tools (default behavior)
uv sync
# Install core dependencies only (no dev tools, no optional dependencies)
uv sync --no-default-groups
# Install with all optional dependencies + dev tools (recommended for contributors)
uv sync --all-extras
# Install with specific optional dependencies + dev tools
uv sync --extra dataset
uv sync --extra train- Core dependencies: Required for basic inference (matting, inpainting)
datasetextra: Required for Crello dataset generation - installed with--extra datasettrainextra: Required for training the matting module - installed with--extra traindevgroup: Development tools (pytest, mypy, ruff, pre-commit) - included by default
Note: uv sync installs core dependencies and dev tools by default. Use uv sync --no-default-groups to exclude dev tools.
LayerD uses pytest markers to separate fast and slow tests, enabling rapid development cycles:
# Fast tests only (recommended for development) - completes in <5 seconds
uv run pytest -m "not slow"
# All tests (includes model loading and inference) - takes 1-2 minutes
uv run pytest
# Only slow tests (model-heavy tests)
uv run pytest -m "slow"# Fast tests only (recommended for development)
uv run pytest -m "not slow"
# All tests
uv run pytest
# Only slow tests
uv run pytest -m "slow"
# Run tests with image output saved
uv run pytest --save-images
# Run tests with custom matting process size
uv run pytest --matting-process-size 512 512
# Full resolution testing (1024x1024, slower but higher quality)
uv run pytest --matting-process-size 1024 1024
# Run specific test
uv run pytest tests/test_basic_decompose.py::test_decompose
# Run with verbose output
uv run pytest -vLayerD uses pytest markers to categorize tests:
slow: Tests that load ML models and run inference (>30s on CPU). Marked tests:test_basic_decompose.py::test_decompose- Tests decomposition with various refine options (4 parametrized tests)test_cli.py::test_run_decompose_success- Tests CLI decompositiontest_cli.py::test_main_success- Tests main entry pointtest_cli.py::test_output_structure- Tests output file structure
integration: Tests requiring real models and external resourcesrequires_gpu: Tests that require GPU/CUDA
Performance: Fast tests (without slow marker) complete in <5 seconds, while slow tests take 1-2 minutes. This 60x speedup enables rapid test-driven development.
- Test fixtures: Defined in
tests/conftest.pymatting_process_size: Configurable matting size (default: 256x256 for 4x speedup vs 1024x1024)layerd_model: Module-scoped LayerD model fixture for efficient test reusesave_images: Flag to save test outputs
- Custom options:
--save-images: Save test outputs totests/output/directory--matting-process-size WIDTH HEIGHT: Override default matting model process size (default: 256 256)
- Test outputs: Saved to
tests/output/(gitignored) - Warning filters: FutureWarnings from timm library are filtered (configured in
pyproject.toml)
The default matting_process_size is 256x256 instead of 1024x1024, providing:
- 4x faster slow tests (1-2 minutes vs 5-8 minutes)
- 60x faster development cycle when using
-m "not slow"(<5 seconds vs 5 minutes) - Maintained test coverage with reduced computational cost
For full-resolution testing (e.g., CI/CD, release validation):
# Run all tests with full 1024x1024 resolution
uv run pytest --matting-process-size 1024 1024
# Run only slow tests with full resolution
uv run pytest -m "slow" --matting-process-size 1024 1024Recommended CI/CD pipeline configuration:
# Fast tests on every commit (development feedback)
- name: Fast Tests
run: uv run pytest -m "not slow"
# Full test suite on pull requests
- name: Full Test Suite
run: uv run pytest
# Full resolution tests nightly or before release
- name: Full Resolution Tests
run: uv run pytest --matting-process-size 1024 1024When writing tests:
- Use pytest fixtures for common setup (especially
layerd_modelfor model reuse) - Add type annotations to all test functions
- Use descriptive test names that explain what is being tested
- Mark slow tests with
@pytest.mark.slowif they load models or run inference - Mark GPU-only tests with
@pytest.mark.requires_gpu - Use the default
matting_process_sizefixture for consistent performance - Clean up any temporary files created during tests
LayerD uses strict mypy configuration:
# Run type checking
uv run mypy src/ tests/ \
vendor/simple-lama-inpainting/simple_lama_inpainting/ \
vendor/cr-renderer/src/cr_renderer/Type checking rules:
disallow_untyped_defs=true- All functions must have type annotationsdisallow_incomplete_defs=true- All parameters and return types must be annotatedno_implicit_optional=true- Optional types must be explicit
All functions must have complete type annotations. This helps catch bugs early and provides better IDE support.
Note: src/layerd/_vendor/ is excluded from type checking (configured in pyproject.toml). We check the source packages in vendor/ but not the bundled copies in _vendor/.
# Run linting
uv run ruff check src/ tests/ vendor/
# Auto-fix linting issues
uv run ruff check src/ tests/ vendor/ --fix# Check code formatting
uv run ruff format src/ tests/ vendor/ --check
# Format code
uv run ruff format src/ tests/ vendor/Before committing code, run:
# Type checking
uv run mypy src/ tests/ \
vendor/simple-lama-inpainting/simple_lama_inpainting/ \
vendor/cr-renderer/src/cr_renderer/
# Linting
uv run ruff check src/ tests/ vendor/
# Formatting
uv run ruff format src/ tests/ vendor/
# Tests
uv run pytestClaude Code users: Use the custom skills for convenience:
/check # Run all quality checks
/check mypy # Just type checking
/fix # Auto-fix linting and format codeSee .claude/skills/README.md for more details.
LayerD bundles two dependencies under layerd._vendor to enable numpy 2.0 compatibility. These dependencies are maintained using git subtree.
vendor/: Source of truth for git subtree operations (tracked in git)src/layerd/_vendor/: Bundled copy for distribution (tracked in git)
Both directories are committed to git to ensure pip install git+... and editable installs work correctly.
When updating vendored dependencies from upstream:
# Update simple-lama-inpainting
git subtree pull --prefix vendor/simple-lama-inpainting \
https://github.com/enesmsahin/simple-lama-inpainting.git main --squash
# Update cr-renderer
git subtree pull --prefix vendor/cr-renderer \
https://github.com/CyberAgentAILab/cr-renderer.git main --squashThe post-merge hook will automatically sync changes. Review and stage them:
git status
git add src/layerd/_vendor/# Use the sync script
./tools/sync-vendor.sh
# Or manually:
rm -rf src/layerd/_vendor/simple_lama_inpainting
cp -r vendor/simple-lama-inpainting/simple_lama_inpainting/ \
src/layerd/_vendor/simple_lama_inpainting/
rm -rf src/layerd/_vendor/cr_renderer
cp -r vendor/cr-renderer/cr_renderer/ \
src/layerd/_vendor/cr_renderer/uv run pytest
uv run mypy src/git add vendor/ src/layerd/_vendor/
git commit -m "chore: update vendored dependencies from upstream"To automatically sync vendor/ → _vendor after git operations:
# Copy the post-merge hook
cp tools/post-merge.sample .git/hooks/post-merge
chmod +x .git/hooks/post-merge- main: Stable branch with released code
- feature branches: Create from main for new features
- bugfix branches: Create from main for bug fixes
Follow conventional commit format:
feat:- New featuresfix:- Bug fixesdocs:- Documentation changestest:- Test additions or changesrefactor:- Code refactoringchore:- Maintenance tasks
Example:
feat: add support for custom matting models
- Add model registry pattern
- Update LayerD class to accept model name
- Add tests for custom model loading
- Fork and clone the repository
- Create a feature branch from main
- Make your changes
- Run pre-commit checks (tests, type checking, linting)
- Commit with descriptive messages
- Push to your fork
- Create a pull request
See CONTRIBUTING.md for detailed contribution guidelines.
# Add a new dependency
uv add <package>
# Add a development dependency
uv add --group dev <package>
# Update dependencies
uv lock --upgrade
# Show installed packages
uv pip listFor debugging during development:
# Run with Python debugger
uv run python -m pdb ./tools/infer.py --input image.png --output-dir outputs/
# Run with verbose logging
uv run layerd --input image.png --output-dir outputs/ --log-level DEBUGUnderstanding the project structure helps with navigation:
LayerD/
├── src/layerd/ # Main source code
│ ├── models/ # Model implementations
│ ├── matting/ # Matting training code
│ ├── data/ # Dataset utilities
│ ├── evaluation/ # Evaluation metrics
│ └── _vendor/ # Bundled dependencies
├── tests/ # Test suite
├── tools/ # Utility scripts
│ ├── infer.py # Batch inference
│ ├── train.py # Training script
│ ├── evaluate.py # Evaluation script
│ └── generate_crello_matting.py # Dataset generation
├── docs/ # Documentation
├── vendor/ # Vendored source (git subtree)
└── data/ # Test images
- Architecture - Code architecture and design patterns
- Testing Best Practices - Detailed testing guidelines (if available)
- Contributing Guidelines - How to contribute to LayerD