Contributing to πiTuna#
Thank you for your interest in contributing to πiTuna! This guide covers everything from setting up your development environment to publishing a new release.
Development Setup#
# Clone the repository
git clone https://github.com/dynamical-inference/ituna.git
cd ituna
# Install in development mode with all dev dependencies
pip install -e .[dev]
# Setup pre-commit hooks (runs linting and formatting on every commit)
pre-commit install
Optional extras:
pip install -e .[datajoint] # DataJoint backend support
pip install -r requirements.txt # install bundled third_party dependency
Branching Conventions#
We follow a release candidate (RC) branch model:
main always releasable, protected
feature/* individual features or improvements
fix/* bug fixes
rc/x.y.z release candidates, created when preparing a release
*-rc alternative RC naming (e.g., v1.2.3-rc)
mainis the stable branch. Every commit onmainshould be in a releasable state. All changes go through pull requests.feature/*andfix/*branches are short-lived. Branch offmain, open a PR back tomain, and delete after merging.rc/*branches are created when preparing a release. See the Release Process section below for details.
Making Changes#
Create a branch from
main:git checkout main && git pull git checkout -b feature/my-feature
Make your changes, commit, and push:
git add . git commit -m "Add my feature" git push -u origin feature/my-feature
Open a pull request to
mainon GitHub. The build workflow will run automatically to check tests, linting, and that the package builds.Once the PR is reviewed and all checks pass, merge it.
Code Style#
We use ruff for both linting and formatting, configured in ruff.toml. Pre-commit hooks run these automatically, but you can also run them manually:
# Check formatting
ruff format --check .
# Auto-format
ruff format .
# Run linter
ruff check .
# Run linter with auto-fix
ruff check --fix .
Key style rules:
Line length: 160 characters
Import sorting: single-line imports, sorted within sections
Python support: 3.8 - 3.14
Running Tests#
# Run all tests
pytest tests/ -v
# Run a specific test file
pytest tests/test_metrics.py -v
# Run with coverage
pytest tests/ -v --cov=ituna
CI Testing Strategy#
The CI pipeline tests different Python versions depending on the context:
Regular PRs: Tests only Python 3.11 for fast feedback
Release candidate PRs (branches starting with
rc/or ending with-rc): Tests the full matrix 3.8 - 3.14Push to main: Tests the full matrix 3.8 - 3.14
This strategy keeps PR checks fast while ensuring comprehensive testing before releases.
Documentation#
The documentation is built using Jupyter Book version 1.x (version 2.x has a completely different build system and is not supported).
Docs Structure#
docs/tutorials/β tutorial notebooks_config.ymlβ Jupyter Book configuration_toc.ymlβ table of contents
Local Build#
# Install jupyter-book (must be version <2)
pip install "jupyter-book<2"
# Build the docs from the project root
jupyter-book build .
# The HTML output will be in _build/html/
# Open in browser:
open _build/html/index.html # macOS
xdg-open _build/html/index.html # Linux
Local Server#
To serve the docs locally with live preview:
cd _build/html
python -m http.server 8080
# Then open http://localhost:8080 in your browser
Using Docker (Recommended)#
For a consistent build environment with auto-rebuild on file changes:
./build.sh
This will:
Build the Docker image with all dependencies
Mount the current directory into the container
Build the docs and start a server at http://localhost:8000
Watch for changes to
.ipynb,.md,.yml, and.pyfiles and rebuild automatically
Press Ctrl+C to stop.
Deploying to GitHub Pages#
# Install required tools
pip install "jupyter-book<2" ghp-import
# Build and publish
jupyter-book build .
ghp-import -n -p -f _build/html
This creates/updates the gh-pages branch and pushes it to GitHub.
Initial setup (one-time): Go to repository Settings > Pages, set the source to the gh-pages branch (root /). The docs will be at: https://dynamical-inference.github.io/ituna/
Release Process#
We use a two-stage release pipeline: a release candidate (RC) branch for staging, followed by a tag push for production.
Version Format#
Stable:
0.4.0Alpha:
0.4.0a1Beta:
0.4.0b1
Tags follow the same format prefixed with v: v0.4.0, v0.4.0a1, v0.4.0b1.
The version is defined in ituna/__init__.py as __version__.
Step-by-step#
1. Prepare the release candidate#
git checkout main && git pull
git checkout -b rc/0.4.0
Bump
__version__inituna/__init__.pyMake any last-minute fixes on this branch
Commit and push:
git add . git commit -m "Bump version to 0.4.0" git push -u origin rc/0.4.0
2. Open a release PR#
Create a PR from
rc/0.4.0tomainAdd the
releaselabel to the PR
3. Verify on TestPyPI#
The publish workflow will automatically build and upload to TestPyPI. Verify the staging version:
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ ituna==0.4.0
python -c "import ituna; print(ituna.__version__)"
Note: If you push more commits to the RC branch, the TestPyPI version will not be automatically updated. Remove and re-add the
releaselabel to trigger a new upload.
4. Merge#
Once tests pass, the staging version looks good, and the PR is reviewed:
Merge the PR using rebase merging
Delete the
rc/0.4.0branch
5. Tag and publish#
git checkout main && git pull
git tag v0.4.0
git push origin v0.4.0
Pushing the tag triggers the publish workflow, which builds and uploads the package to PyPI.
6. Verify#
pip install ituna==0.4.0
python -c "import ituna; print(ituna.__version__)"
Quick Reference#
Step |
Action |
|---|---|
Branch |
|
Bump version |
Edit |
PR |
Open PR to |
Staging |
Verify on TestPyPI |
Merge |
Rebase merge, delete branch |
Tag |
|
Verify |
|