🌐 English|한국어

Developer Guide

This guide is for developers who want to contribute to or extend CTHarvester.

Architecture Overview

Module Structure

CTHarvester follows a modular architecture:

CTHarvester/
├── core/                      # Core business logic
│   ├── progress_tracker.py        # Progress tracking
│   ├── progress_manager.py        # Progress management
│   ├── thumbnail_manager.py       # Thumbnail coordination
│   ├── thumbnail_generator.py     # Thumbnail generation logic
│   ├── thumbnail_worker.py        # Worker threads
│   ├── sequential_processor.py    # Sequential processing (Phase 4.1)
│   ├── volume_processor.py        # Volume processing
│   └── worker_manager.py          # Worker management
├── ui/                        # User interface
│   ├── main_window.py             # Main application window (789 lines)
│   ├── ctharvester_app.py         # Custom QApplication subclass
│   ├── handlers/                  # UI handler modules (Phase 4)
│   │   ├── thumbnail_creation_handler.py  # Thumbnail generation (Phase 4.2)
│   │   ├── directory_open_handler.py      # Directory opening (Phase 4.3)
│   │   ├── view_manager.py                # 3D view management (Phase 4.4)
│   │   ├── export_handler.py              # Export operations
│   │   ├── file_handler.py                # File operations
│   │   └── settings_handler.py            # Settings management
│   ├── dialogs/                   # Dialog windows
│   │   ├── progress_dialog.py         # Progress display
│   │   ├── info_dialog.py             # Information dialogs
│   │   └── shortcut_dialog.py         # Keyboard shortcuts
│   ├── widgets/                   # Custom widgets
│   │   ├── mcube_widget.py            # 3D marching cubes viewer
│   │   ├── object_viewer_2d.py        # 2D image viewer
│   │   └── vertical_stack_slider.py   # Range slider
│   └── setup/                     # UI setup modules
│       └── main_window_setup.py       # Window initialization
├── utils/                     # Utility functions
│   ├── settings_manager.py        # YAML settings
│   ├── common.py                  # Common utilities
│   ├── ui_utils.py                # UI helper functions
│   ├── file_utils.py              # File utilities
│   └── image_utils.py             # Image processing utilities
├── config/                    # Configuration
│   ├── constants.py               # Application constants
│   ├── settings.yaml              # Default settings
│   ├── shortcuts.py               # Keyboard shortcuts
│   └── tooltips.py                # Tooltip definitions
├── security/                  # Security modules
│   └── file_validator.py         # File validation & path traversal prevention
└── tests/                     # Test suite (1,150 tests)
    ├── integration/               # Integration tests
    ├── property/                  # Property-based tests
    └── test_*.py                  # Unit tests

Design Principles

  1. Separation of Concerns: UI, business logic, and data handling are separate

  2. Modularity: Each module has a single, well-defined responsibility

  3. Testability: Core logic is independent of UI for easy testing

  4. Thread Safety: Proper synchronization for multithreaded operations

  5. Security First: Input validation and secure file operations

Key Components

Progress Tracking:

  • SimpleProgressTracker: Linear progress with ETA

  • ProgressManager: Weighted multi-level progress

  • Signal/slot connections for UI updates

Thumbnail Generation:

  • ThumbnailCreationHandler: Orchestrates Rust/Python thumbnail generation (Phase 4.2)

  • ThumbnailGenerator: Core thumbnail generation logic

  • ThumbnailManager: Coordinates worker threads

  • ThumbnailWorker: Processes individual thumbnails

  • SequentialProcessor: Python fallback sequential processing (Phase 4.1)

  • Support for both Rust (high-performance) and Python (fallback) implementations

UI Handlers (Phase 4 Refactoring):

  • ThumbnailCreationHandler: Manages thumbnail generation workflows

  • DirectoryOpenHandler: Handles directory selection and loading

  • ViewManager: Manages 3D view updates and synchronization

  • ExportHandler: Manages export operations

  • FileHandler: File operations and validation

  • SettingsHandler: Window settings persistence

Settings Management:

  • YAML-based configuration

  • Platform-independent storage

  • Import/Export functionality

  • Dot notation access (settings.get('app.language'))

Security:

  • SecureFileValidator: Path traversal prevention

  • Whitelist-based file extension validation

  • Safe file operations

Development Setup

Prerequisites

  • Python 3.8+

  • Git

  • Virtual environment tool (venv or conda)

  • Optional: Rust toolchain for building native module

Setting Up Development Environment

  1. Clone and setup:

    git clone https://github.com/yourusername/CTHarvester.git
    cd CTHarvester
    
    # Create virtual environment
    python -m venv venv
    source venv/bin/activate  # Linux/macOS
    # or
    venv\\Scripts\\activate    # Windows
    
    # Install dependencies
    pip install -r requirements.txt
    pip install -r requirements-dev.txt  # Development dependencies
    
  2. Install pre-commit hooks:

    pre-commit install
    
  3. Run tests:

    pytest tests/
    

Code Style and Standards

Python Style Guide

We follow PEP 8 with some modifications:

  • Line length: 100 characters (not 79)

  • Use double quotes for strings

  • Use type hints for function signatures

  • Use Google-style docstrings

Example:

def process_image(
    image_path: str,
    threshold: int = 128,
    invert: bool = False
) -> np.ndarray:
    """Process a single CT image.

    Args:
        image_path: Path to the image file.
        threshold: Grayscale threshold value (0-255).
        invert: Whether to invert grayscale values.

    Returns:
        Processed image as numpy array.

    Raises:
        FileNotFoundError: If image_path doesn't exist.
        ValueError: If threshold is out of range.
    """
    # Implementation
    pass

Docstring Style

Use Google-style docstrings for all public APIs:

def function_name(param1: type1, param2: type2) -> return_type:
    """Short one-line summary.

    Longer description if needed. Can span multiple paragraphs.

    Args:
        param1: Description of param1.
        param2: Description of param2.

    Returns:
        Description of return value.

    Raises:
        ExceptionType: When this exception is raised.

    Example:
        >>> result = function_name("foo", 42)
        >>> print(result)
        'expected output'
    """

Type Hints

Use type hints for all function signatures:

from typing import Optional, List, Dict, Tuple

def process_files(
    files: List[str],
    options: Optional[Dict[str, Any]] = None
) -> Tuple[int, int]:
    """Process multiple files."""
    pass

Testing

Test Organization

Tests are organized by module:

tests/
├── test_progress_tracker.py
├── test_thumbnail_manager.py
├── test_settings_manager.py
└── test_file_validator.py

Running Tests

Run all tests:

pytest

Run specific test file:

pytest tests/test_settings_manager.py

Run with coverage:

pytest --cov=. --cov-report=html

Run specific test:

pytest tests/test_settings_manager.py::test_get_nested_setting

Writing Tests

Example test structure:

import pytest
from core.progress_tracker import SimpleProgressTracker, ProgressInfo

class TestSimpleProgressTracker:
    """Tests for SimpleProgressTracker class."""

    def test_initialization(self):
        """Test tracker initialization."""
        tracker = SimpleProgressTracker(total_items=100)
        assert tracker.completed_items == 0
        assert tracker.total_items == 100

    def test_update_progress(self):
        """Test progress update."""
        tracker = SimpleProgressTracker(total_items=100)
        tracker.update(increment=10)
        assert tracker.completed_items == 10

    def test_eta_calculation(self):
        """Test ETA calculation after sufficient samples."""
        results = []

        def callback(info: ProgressInfo):
            results.append(info)

        tracker = SimpleProgressTracker(
            total_items=100,
            callback=callback
        )

        for i in range(10):
            time.sleep(0.1)
            tracker.update()

        # After min_samples_for_eta, should have ETA
        assert results[-1].eta_seconds is not None

    @pytest.mark.parametrize("total,increment", [
        (100, 1),
        (1000, 10),
        (50, 5),
    ])
    def test_various_increments(self, total, increment):
        """Test with various total/increment combinations."""
        tracker = SimpleProgressTracker(total_items=total)
        for i in range(0, total, increment):
            tracker.update(increment=increment)
        assert tracker.completed_items == total

Test Coverage Goals

  • Overall coverage: >70%

  • Core modules: >80%

  • Security modules: >90%

Contributing

Contribution Workflow

  1. Fork and Clone:

    • Fork the repository on GitHub

    • Clone your fork locally

    • Add upstream remote:

      git remote add upstream https://github.com/original/CTHarvester.git
      
  2. Create Feature Branch:

    git checkout -b feature/your-feature-name
    
  3. Make Changes:

    • Write code

    • Add tests

    • Update documentation

    • Run tests: pytest

    • Check style: flake8 or black --check .

  4. Commit:

    git add .
    git commit -m "feat: Add your feature description"
    

    Follow conventional commits format:

    • feat:: New feature

    • fix:: Bug fix

    • docs:: Documentation changes

    • refactor:: Code refactoring

    • test:: Adding tests

    • chore:: Maintenance tasks

  5. Push and Create PR:

    git push origin feature/your-feature-name
    
    • Create pull request on GitHub

    • Fill out PR template

    • Link related issues

    • Wait for review

Code Review Process

All code changes go through review:

  1. Automated Checks:

    • Tests must pass

    • Code coverage must not decrease

    • Style checks must pass

  2. Manual Review:

    • At least one approving review required

    • Address review comments

    • Update as needed

  3. Merge:

    • Squash and merge preferred

    • Delete branch after merge

Pull Request Guidelines

Good PR:

  • Focused on single feature/fix

  • Includes tests

  • Updates documentation

  • Clear description

  • Links to related issues

PR Template:

## Description
Brief description of changes

## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Refactoring

## Testing
- [ ] Tests added/updated
- [ ] All tests passing
- [ ] Manual testing performed

## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review performed
- [ ] Documentation updated
- [ ] No new warnings

## Related Issues
Closes #123

Building and Packaging

Building Rust Module

cd rust_thumbnail
cargo build --release
cd ..

The compiled library will be placed in target/release/.

Creating Executable

Using PyInstaller:

# Windows
pyinstaller --onefile --noconsole --icon=CTHarvester_64.png CTHarvester.py

# Linux/macOS
pyinstaller --onefile --icon=CTHarvester_64.png CTHarvester.py

Output:

  • Executable in dist/ directory

  • Standalone, no Python required

Building Documentation

cd docs
make html

Output in docs/_build/html/.

Release Process

  1. Update Version:

    • Update config/constants.py

    • Update docs/conf.py

    • Update setup.py (if using)

  2. Update Changelog:

    • Add release notes

    • List all changes since last release

  3. Create Release:

    git tag -a v0.3.0 -m "Release v0.3.0"
    git push origin v0.3.0
    
  4. Build Artifacts:

    • Build executables for all platforms

    • Build documentation

    • Create source distribution

  5. Publish Release:

    • Create GitHub release

    • Attach built artifacts

    • Copy changelog to release notes

    • Mark as latest release

Debugging Tips

Logging

CTHarvester uses Python’s logging module:

import logging
logger = logging.getLogger(__name__)

logger.debug("Detailed information")
logger.info("General information")
logger.warning("Warning message")
logger.error("Error occurred")

Set log level in settings or via command line.

Common Debugging Scenarios

Threading Issues:

  • Use QMutexLocker for thread-safe operations

  • Check for race conditions with threading.current_thread()

  • Use logging instead of print() in threads

Memory Leaks:

  • Use memory_profiler to track memory usage

  • Check for circular references

  • Use weak references where appropriate

Performance Issues:

  • Profile with cProfile

  • Use line_profiler for line-by-line profiling

  • Check I/O operations (often the bottleneck)

Qt/GUI Issues:

  • Only update UI from main thread

  • Use signals/slots for cross-thread communication

  • Check event loop is running

Resources

Documentation

Tools

  • pytest: Testing framework

  • black: Code formatter

  • flake8: Linter

  • mypy: Type checker

  • coverage.py: Coverage reporting

  • PyInstaller: Executable builder

Community

  • GitHub Issues: Bug reports and feature requests

  • Discussions: Questions and general discussion

  • Pull Requests: Code contributions

  • Wiki: Additional documentation

Getting Help

  1. Check this documentation

  2. Search existing issues

  3. Ask in GitHub Discussions

  4. Create new issue if needed

When asking for help, include:

  • Python version

  • Operating system

  • CTHarvester version

  • Error message (full traceback)

  • Minimal reproduction steps

  • What you’ve tried