🌐 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        # User preferences (preferences.json)
│   ├── paths.py                   # User-data locations (single owner)
│   ├── 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
│   ├── shortcuts.py               # Keyboard shortcuts
│   └── tooltips.py                # Tooltip definitions
├── security/                  # Security modules
│   └── file_validator.py         # File validation & path traversal prevention
└── tests/                     # Test suite (1,295 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:

  • JSON-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

  • ruff: Linter and formatter (replaced black, isort, flake8, pyupgrade and pylint)

  • mypy: Type checker

  • bandit: Security linter

  • coverage.py: Coverage reporting

  • PyInstaller: Executable builder

In-repo notes

Longer-form developer references live as Markdown in the repository rather than in this manual, because they are for people working on CTHarvester rather than using it. They are not part of this site – see docs/README.md for the convention.

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