Development¶
Development Environment¶
Docker (Recommended)¶
Start the development environment with bind-mounted source code:
The development compose file:
- Builds from the local Dockerfile
- Mounts the source tree at
/app - Uses a named volume for
.venv(avoids host/container venv conflicts) - Runs
sleep infinityso you can exec into the container and start the service manually
Inside the container, start the server in debug mode:
Local Setup¶
Install the package with test dependencies:
Running the Server¶
Start the service in debug mode for development:
The --debug flag enables hot-reloading and verbose logging. Access http://localhost:1122/docs for the interactive Swagger UI.
Testing¶
Adding Tests¶
- Add tests to the
test_<module>.pyfile corresponding to the target module - Naming convention:
test_<target>_<condition>_<expected_result>() - Use hypothesis
@givenwhen property-based testing is applicable - Confirm PASS with
uv run pytest -v - Confirm lint-clean with
uv run ruff check tests/anduv run ruff format --check tests/ - Optionally verify detection power with
uv run mutmut run --paths-to-mutate sapporo/<module>.py
Running Tests¶
# Run all tests
uv run pytest
# Verbose output
uv run pytest -v
# Specific file
uv run pytest tests/unit/test_utils.py
# Specific test
uv run pytest tests/unit/test_utils.py::test_now_str_returns_rfc3339_utc_format
# Run in random order (check for order dependencies)
uv run pytest -p randomly -v
# Exclude slow tests
uv run pytest -m "not slow"
Mutation Testing¶
# Run according to [tool.mutmut] settings in pyproject.toml
uv run mutmut run
# View results
uv run mutmut results
# Show details of a survived mutant
uv run mutmut show <mutant_id>
Integration Tests¶
Integration tests require a running sapporo instance with Docker-in-Docker
support (e.g., via compose.dev.yml). Each test file exercises a specific
workflow engine:
| Test File | Engine | Workflow Type |
|---|---|---|
test_cwltool.py |
cwltool | CWL |
test_toil.py |
toil | CWL |
test_ep3.py |
ep3 | CWL |
test_cromwell.py |
cromwell | WDL |
test_nextflow.py |
nextflow | NFL |
test_snakemake.py |
snakemake | SMK |
test_ro_crate.py |
all of the above | (multi-engine RO-Crate validation) |
Run integration tests inside the development container:
docker compose -f compose.dev.yml up -d --build
docker compose -f compose.dev.yml exec app bash
# Start sapporo in background
sapporo --debug &
# Run all integration tests
pytest tests/integration/ -v
# Run a specific engine
pytest tests/integration/test_toil.py -v
# Exclude slow tests (large workflows, roc-validator)
pytest tests/integration/ -v -m "not slow"
Linting and Type Checking¶
The project uses ruff for linting/formatting and mypy for type checking. Configuration is in pyproject.toml.
# Lint
uv run ruff check .
# Format check
uv run ruff format --check .
# Auto-fix lint issues
uv run ruff check --fix .
# Auto-format
uv run ruff format .
# Type check
uv run mypy
OpenAPI Spec Generation¶
The OpenAPI specification file (openapi/sapporo-wes-spec-X.X.X.yml) is generated from the FastAPI application. Regenerate it after changing schemas, endpoint descriptions, or the spec version:
The generated file should be committed to the repository.
Spec Version¶
SAPPORO_WES_SPEC_VERSION in sapporo/config.py is the single source of truth for the sapporo-wes spec version. This constant is referenced throughout the codebase to produce the **sapporo-wes-X.X.X extension:** markers in OpenAPI descriptions, info.version, and example values.
To bump the spec version:
- Update
SAPPORO_WES_SPEC_VERSIONinsapporo/config.py - Regenerate the spec:
uv run sapporo-cli generate-openapi - Rename the output file if the major/minor version changed
Release Process¶
Version Management¶
- The git tag is the single source of truth for the package version (
hatch-vcs) - At runtime, the version is obtained via
importlib.metadata.version("sapporo") - Docker image version is injected by CI from the tag name with
--build-arg VERSION=...andSETUPTOOLS_SCM_PRETEND_VERSION
Release Steps¶
- Create a PR to
mainand merge - Create a version tag on the
mainbranch and push:
- The tag push triggers
release.ymlautomatically: - Publish PyPI package (Trusted Publishing)
- Build and push multi-architecture Docker image (ghcr.io)
- Create GitHub Release (auto-generated release notes)
Differences from 1.x¶
- Changed from Flask to FastAPI
- Updated base GA4GH WES from 1.0.0 to 1.1.0
- Reorganized authentication with switchable methods
- Added SQLite database for faster
GET /runsqueries - Organized Python and Docker toolchain
- Simplified
executable_workflows.jsonto a list ofworkflow_urls - Full support for automatic run directory cleanup
- See the sapporo-wes-2.0.0 specification for detailed API changes