Contributing to Thesis Imaging Pipeline#

Thank you for your interest in contributing! This document provides guidelines and instructions.

Prerequisites#

  • Python 3.11+

  • Git

  • Conda or venv

  • FSL and ANTs (for testing preprocessing)

Getting Started#

1. Fork and Clone#

git clone https://gitlab.liu.se/YOUR_USERNAME/thesis.git
cd thesis
git remote add upstream https://gitlab.liu.se/pasje442/thesis.git

2. Create Development Environment#

conda env create -f environment.yml
conda activate thesis
pip install -e ".[dev,docs]"
pre-commit install

3. Create Feature Branch#

git checkout -b feature/my-feature
# or
git checkout -b fix/my-fix

Development Workflow#

Code Style#

We follow PEP 8 with Black formatting:

# Format code
make format

# Check formatting
make lint

# Type checking
make type-check

# Run all checks
make check

Testing#

All code must have tests:

# Run all tests
make test

# Run with coverage
make test-cov

# Run specific test
pytest tests/unit/test_my_test.py::TestClass::test_method -v

Test Coverage Requirement: Aim for >80% coverage on new code.

Commit Messages#

Follow conventional commits:

<type>(<scope>): <subject>

<body>

<footer>

Types:

  • feat: New feature

  • fix: Bug fix

  • docs: Documentation

  • test: Test additions/changes

  • refactor: Code refactoring

  • perf: Performance improvements

  • ci: CI/CD changes

Example:

feat(preprocessing): add Gibbs ringing artifact removal

Implement PATCH algorithm for Gibbs artifact correction.
Includes comprehensive tests and documentation.

Closes #42

Do not manually edit CHANGELOG.md or bump the version. After your feature commits land, run make bump (commitizen) to increment the dev version and update the changelog atomically. Preview with make bump-dry, then push the tag with git push --follow-tags.

Before Pushing#

# Update from upstream
git fetch upstream
git rebase upstream/main

# Run all checks
make check

# Run tests
make test

# Push
git push origin feature/my-feature

Pull Request Process#

  1. Update Documentation

    • Add docstrings to new functions

    • Update relevant documentation files

    • Add examples if applicable

  2. Add Tests

    • Unit tests for new functions

    • Integration tests for pipelines

    • Test fixtures for common setup

  3. Code Review

    • Address reviewer feedback

    • Keep commits clean and logical

    • Maintain discussion in PR

  4. Merge

    • Squash commits if requested

    • Delete feature branch after merge

Adding a New Workflow#

The full decorator-API reference — @workflow / @requires / @produces / @verify, the path-declaration types, config namespaces, and the inputnode/outputnode contracts — lives in custom_workflows.md. This section is the contributor checklist for vendoring a workflow into src/thesis/ (rather than running it out-of-tree); follow it alongside that guide instead of restating the API here.

  1. Create the package src/thesis/workflows/my_workflow/.

  2. Wire up self-registration. A workflow registers itself the moment its module is imported (the @workflow decorator runs at import time), so the package __init__.py must import the module for its side effect:

    # src/thesis/workflows/my_workflow/__init__.py
    """My workflow package."""
    
    from . import workflow as _workflow  # noqa: F401  (side effect: registration)
    
  3. Implement the factory in workflow.py using the decorator API (see custom_workflows.md for the full annotated example, and Owning a config section if the workflow claims its own top-level YAML key). Add a @verify(check_fn) preflight check when the implicit existence checks from @requires are not enough (e.g. cross-field validation). src/thesis/workflows/atlas/workflow.py is the reference cohort example.

  4. Split large workflows early. Keep workflow.py focused on Nipype graph construction and the decorator stack; move heavier concerns (I/O helpers, parameter models, statistic builders) into private helper modules. The atlas workflow is the reference layout: workflow.py, compute.py, _params.py, _io.py, _statistics.py.

  5. Add tests in tests/unit/ (and tests/integration/ if external tools are involved). At minimum assert that the module registers and that the factory returns a nipype.Workflow:

    # tests/unit/test_my_workflow.py
    from thesis.core.context import ProcessingContext
    from thesis.core.registry import WORKFLOW_REGISTRY
    # Importing the module triggers @workflow registration.
    from thesis.workflows.my_workflow import workflow as _my_workflow  # noqa: F401
    
    
    class TestBuildMyWorkflow:
        def test_registers(self):
            assert WORKFLOW_REGISTRY.has("my_workflow")
    
        def test_returns_nipype_workflow(self, mock_config, tmp_path):
            ctx = ProcessingContext(
                patient_id="TEST001",
                config=mock_config,
                input_dir=tmp_path,
                output_dir=tmp_path,
            )
            entry = WORKFLOW_REGISTRY.get("my_workflow")
            wf = entry.factory(mock_config, ctx)
            assert wf.name.startswith("my_workflow")
    
  6. Document. Add Google-style docstrings to the factory and public helpers; add the workflow to docs/guides/workflows.md and its “Choosing a workflow” table; add an API reference page docs/api/workflows.my_workflow.rst and link it from docs/api/workflows.rst.

Vendor into the package, or keep it out-of-tree? The steps above vendor the workflow into src/thesis/. For experiments or one-off workflows that don’t belong in the package, prefer an out-of-tree script run via thesis run --script ./my_workflow.py — it uses the same decorator API without touching the package. See custom_workflows.md, and examples/plain_nipype_workflow.py + examples/annotated_nipype_workflow.py for a before/after pair showing a plain Nipype script alongside its annotated form.

Running Existing Tests#

# All tests
pytest tests/

# Unit tests only (no external tools required)
pytest tests/unit/ -v

# Integration tests (may require FSL / ANTs)
pytest tests/integration/ -v

# Specific test file
pytest tests/unit/test_config_validators.py -v

# Specific test class or method
pytest tests/unit/test_config_validators.py::TestPathConfig::test_defaults -v

# With coverage
pytest tests/ --cov=src/thesis --cov-report=html

# Re-run only the last failures
pytest --lf

# Stop on first failure
pytest -x

Documentation#

Building Docs Locally#

sphinx-build -W -b html docs docs/build/html
open docs/build/html/index.html

Adding Documentation#

  1. Create .md or .rst file in docs/guides/

  2. Update docs/index.rst with link

  3. Build and verify locally

Reporting Issues#

Open an issue on the GitLab project (https://gitlab.liu.se/pasje442/thesis/-/issues) and provide:

  • Clear description

  • Steps to reproduce

  • Expected vs actual behavior

  • Environment (OS, Python version, etc.)

  • Error messages and logs

Getting Help#

Code of Conduct#

Our Pledge#

We are committed to providing a welcoming and inspiring community for all.

Standards#

Examples of behavior that contributes to a positive environment:

  • Using welcoming and inclusive language

  • Being respectful of different viewpoints

  • Accepting constructive criticism

  • Focusing on what’s best for the community

  • Showing empathy towards others

Unacceptable Behavior#

Including but not limited to:

  • Harassment or discrimination

  • Personal attacks

  • Trolling or insulting comments

  • Publishing others’ private information

  • Other conduct that could reasonably be considered inappropriate


Thank you for making this project better! 🎉