Development Workflow¶
This guide covers the day-to-day development workflow for pyhs3, including tools, commands, and best practices.
Development Tools¶
We use several tools for development:
pixi: Package management, environment management, and task running
pre-commit: Git hooks for code quality
pytest: Testing framework
ruff: Fast Python linter and formatter
mypy: Static type checking
sphinx: Documentation generation
Working with pixi¶
pixi provides reproducible development environments and task automation. Tasks automatically use the correct environment, so you don’t need to specify environments when running tasks.
Installing pixi¶
Follow installation instructions at https://pixi.prefix.dev/latest/
Quick Start¶
After cloning the repository:
pixi install # Install all dependencies and pyhs3 in editable mode
This sets up all environments (test, docs, dev) and installs pyhs3 automatically.
Available Tasks¶
View all available tasks:
pixi task list
Testing tasks:
test: Run quick tests (skip slow and pydot)test-cov: Run quick tests with coveragetest-slow: Run tests including slow teststest-pydot: Run tests including pydot teststest-all: Run all tests with coverage (slow + pydot)test-docstrings: Run doctests in source modulestest-docs: Run doctests in README and docs/check-docstrings: Check docstring style
Documentation tasks:
docs-build: Build documentation (static)docs-linkcheck: Check documentation for broken linksdocs-serve: Build and serve documentationdocs-watch: Build and serve documentation with live reload (recommended for development)docs-clean: Clean documentation build artifactsdocs-api: Regenerate API documentation
Linting tasks:
pre-commit: Run pre-commit hooks on all filespylint: Run PyLint on pyhs3 packagelint: Run all linting (pre-commit + pylint)
Development tasks:
pre-commit-install: Install pre-commit git hookspre-commit-update: Update pre-commit hook versionsbuild-clean: Clean build artifactsbuild: Build SDist and wheel distributionsbuild-check: Build and validate package with twine
Composite tasks:
check: Quick check (lint + basic tests)check-all: Comprehensive check (lint + all tests)
Running Tasks¶
Run tasks using pixi run:
# Testing
pixi run test
pixi run test-cov
pixi run test-all
# Linting
pixi run lint
pixi run pre-commit
pixi run pylint
# Documentation
pixi run docs-watch
pixi run docs-build
# Quick checks
pixi run check
pixi run check-all
Pass additional arguments directly:
pixi run test tests/test_distributions.py -v
pixi run pylint --output-format=json
Environments¶
pixi manages three environments automatically:
test: Testing environment (includes ROOT, cms-combine, jax, pytest)docs: Documentation environment (includes Sphinx and extensions)dev: Development environment (combines test + docs + dev tools)
You don’t need to manually activate or switch environments - tasks automatically use the correct environment.
Pre-commit Hooks¶
Setting Up Pre-commit¶
After running pixi install, configure pre-commit hooks:
pixi run pre-commit-install
This installs git hooks that automatically run before each commit. All tools (ruff, mypy, etc.) are managed by pixi, so you don’t need to install them separately.
Running Pre-commit¶
Run hooks on changed files:
pixi run pre-commit
Run hooks on all files:
pixi run pre-commit --all-files
Pre-commit Workflow¶
Let pre-commit handle imports and formatting automatically:
Make your code changes
Add new imports if needed (don’t remove unused imports manually)
Commit your changes
Pre-commit will automatically: - Remove unused imports - Sort imports - Format code - Fix other issues
If pre-commit makes changes, re-add files and commit again
If unstaged changes conflict with hook fixes:
git add file1 file2
git commit -m "your message"
Code Linting¶
Using ruff¶
ruff is our primary linter and formatter. It’s extremely fast and handles most code quality issues. We enable many ruff rules (see pyproject.toml).
The easiest way to run ruff is through pre-commit:
pixi run pre-commit
For manual use, ruff is available in the pixi environment. You can run it directly after pixi install:
# Check code
ruff check src/pyhs3 tests
# Auto-fix issues
ruff check --fix src/pyhs3 tests
# Format code
ruff format src/pyhs3 tests
Type Checking¶
Using mypy¶
We enforce strict type checking with mypy. Our mypy configuration is in pyproject.toml. It runs automatically with pre-commit, or you can run it manually after pixi install:
mypy src/pyhs3
Testing with Specific Python Versions¶
To run tests with a specific Python version, use the environment name:
# Python 3.10
pixi run -e py310 test
# Python 3.11
pixi run -e py311 test
# Python 3.12
pixi run -e py312 test
# Python 3.13
pixi run -e py313 test
# Python 3.14
pixi run -e py314 test
The default test task runs quick tests (skips slow and pydot tests). For comprehensive testing:
# Run all tests (including slow and pydot)
pixi run -e py311 test-all
# Run with coverage
pixi run -e py311 test-cov
Building Documentation¶
Local Documentation Build¶
Build documentation:
pixi run docs-build
Build and serve with live reload:
pixi run docs-watch
This will:
Build the documentation
Start a local web server
Open your browser automatically
Reload when you make changes
Regenerate API Documentation¶
Regenerate API docs from source code:
pixi run docs-api
Clean Documentation Build¶
Clean documentation build artifacts:
pixi run docs-clean
Documentation Structure¶
Documentation sources are in docs/.
Testing Workflow¶
Quick Testing¶
During development, run tests frequently using pixi tasks:
# Quick tests (skip slow and pydot)
pixi run test
# All tests with coverage
pixi run test-all
# Tests with coverage report
pixi run test-cov
For specific tests, pass additional arguments directly:
# Run specific test file
pixi run test tests/test_distributions.py -v
# Run specific test
pixi run test tests/test_distributions.py::TestGaussianDistribution::test_pdf_evaluation
Advanced: Direct pytest Usage¶
After pixi install, pytest is available in the environment for direct use:
pytest -v
pytest tests/test_distributions.py
pytest -m "not slow"
With Coverage¶
Use pixi tasks for coverage:
# Quick tests with coverage
pixi run test-cov
# All tests with coverage
pixi run test-all
Or run pytest directly with coverage options:
pytest --cov=pyhs3 --cov-report=html
open htmlcov/index.html
See Testing Guide for comprehensive testing guide.
Common Development Tasks¶
Adding a New Distribution¶
Create distribution class in
src/pyhs3/distributions/Add type hints and docstrings
Write unit tests in
tests/test_distributions.pyAdd integration test if needed
Update documentation if it’s a public API
Run tests and linting:
pixi run check
Commit with semantic message:
feat: add XYZ distribution
Adding a New Function¶
Create function class in
src/pyhs3/functions/Add type hints and docstrings
Write unit tests in
tests/test_functions.pyUpdate documentation
Run tests and linting
Commit:
feat: add XYZ function
Fixing a Bug¶
Write a failing test that reproduces the bug
Run test to confirm failure
Fix the bug with minimal changes
Run test to confirm fix
Check for regression with full test suite
Commit:
fix: correct XYZ behavior
Updating Documentation¶
Edit relevant
.rstfiles indocs/Build docs locally to preview:
pixi run docs-serveCheck for broken links and formatting
Commit:
docs: update XYZ documentation
Troubleshooting¶
Pre-commit Hook Failures¶
If pre-commit hooks fail:
Read the error message - it usually explains what’s wrong
Let hooks fix issues - many hooks auto-fix problems
Re-add and re-commit - after auto-fixes, stage changes again
Check for conflicts - ensure you don’t have uncommitted changes
Common issues:
Import sorting: Let ruff/isort handle it
Formatting: Let ruff format handle it
Type errors: Fix mypy errors before committing
Trailing whitespace: Auto-fixed by hooks
mypy Errors¶
If mypy reports type errors:
Add missing type hints
Use
from __future__ import annotationsat the top of filesImport types from
typingmoduleUse
Anysparingly for truly dynamic typesCheck mypy documentation: https://mypy.readthedocs.io/
Test Failures¶
If tests fail:
Read the error message and traceback
Run the specific test to isolate the issue
Use pytest verbosity:
pytest -vvfor more detailCheck for environment issues - ensure clean venv
Verify test data - ensure test files are present
CI Failures¶
If CI fails but tests pass locally:
Check the CI logs on GitHub
Look for platform-specific issues (Windows vs Linux vs macOS)
Verify all dependencies are in
pyproject.tomlandpixi.tomlRun pre-commit:
pixi run pre-commitTest with pixi to match CI environment:
pixi run check-all
Documentation Build Failures¶
If documentation fails to build:
Check Sphinx warnings - treat warnings as errors
Verify reStructuredText syntax - check for formatting errors
Test locally:
pixi run docs-buildCheck for broken links in documentation
Validate cross-references to ensure they resolve
Environment Issues¶
If you have dependency or environment issues:
Reinstall with pixi:
pixi clean pixi install
Update pixi:
pixi self-updateClear caches:
rm -rf .pytest_cache .mypy_cache .ruff_cache rm -rf docs/_build pixi clean cache
Performance Tips¶
Faster Testing¶
Use
pixi run testfor quick tests (skips slow and pydot tests)Run specific tests:
pixi run test tests/test_specific.pyAfter
pixi install, pytest is available for direct use when you need fine-grained controlUse pytest-xdist for parallel testing:
pytest -n autoUse
--lfto run last failed tests first:pytest --lf
Faster Linting¶
After
pixi install, ruff is available directly for very fast iterationUse
ruff check --fixfor quick auto-fixes during developmentRun full
pixi run pre-commitbefore pushing to ensure all checks pass
Editor Integration¶
VS Code¶
Recommended extensions:
Python (Microsoft)
Pylance
Ruff
mypy
Recommended settings:
{
"python.linting.enabled": true,
"python.linting.ruffEnabled": true,
"python.formatting.provider": "ruff",
"python.linting.mypyEnabled": true,
"editor.formatOnSave": true
}
PyCharm¶
Configure:
Enable ruff as external tool
Configure mypy as external tool
Enable pytest as test runner
Set up pre-commit as file watcher
Best Practices¶
Daily Workflow¶
Pull latest changes:
git pull origin mainCreate/switch to feature branch:
git checkout -b feat/my-featureMake small, focused changes
Write tests as you go
Run tests frequently:
pixi run testCommit often with semantic messages
Run checks before pushing:
pixi run checkPush and create PR when ready
Code Quality¶
Write simple, readable code over clever code
Add type hints to all functions
Write docstrings for public APIs
Test edge cases and error conditions
Keep functions small and focused
Avoid code duplication through refactoring
Git Hygiene¶
Commit frequently with logical changes
Write descriptive commit messages
Don’t commit large files or secrets
Use
.gitignoreto exclude generated filesKeep branches up to date with main
Getting Help¶
If you’re stuck:
Check this guide and contributing guide
Review Testing Guide for testing questions
Read Architecture Overview to understand the codebase
Open a discussion on GitHub
Check tool documentation: - pytest: https://docs.pytest.org/en/stable/ - mypy: https://mypy.readthedocs.io/en/stable/ - ruff: https://docs.astral.sh/ruff/ - sphinx: https://www.sphinx-doc.org/