Skip to content

Development Tooling

canVODpy uses a modern Python toolchain built almost entirely on the Astral ecosystem.

  •   uv


    Replaces pip, venv, pip-tools, and twine in a single binary. Manages Python versions, virtual environments, dependency resolution, and builds.

    astral.sh/uv

  •   ruff


    Linter + formatter in one tool. Implements 700+ rules from flake8, pylint, black, and isort at 10–100× their speed.

    astral.sh/ruff

  •   ty


    Type checker replacing mypy. Early development (alpha) but already significantly faster for large codebases.

  •   just


    Task runner with simpler syntax than Make. All common development tasks — test, check, docs, config — are just <command> away.

    github.com/casey/just


Core Tools

uv sync                  # Install all dependencies (workspace-aware)
uv add numpy             # Add a runtime dependency
uv add --dev pytest      # Add a dev dependency
uv run pytest            # Run in the managed environment
uv build                 # Build a wheel
uv publish               # Publish to PyPI

Configuration in pyproject.toml:

[project]
dependencies = ["numpy>=2.0", "xarray>=2024.0"]

[dependency-groups]
dev = ["pytest>=8.0", "ruff>=0.14", "ty>=0.0.1"]

Builds wheel and sdist with native namespace package support:

# packages/canvod-readers/pyproject.toml
[build-system]
requires      = ["uv_build>=0.9.17,<0.10.0"]
build-backend = "uv_build"

[tool.uv.build-backend]
module-name = "canvod.readers"   # dot → namespace package

Note

canvod-utils uses hatchling as its build backend — the only exception in the monorepo.

ruff check .          # Lint
ruff check . --fix    # Lint with auto-fix
ruff format .         # Format

Configuration (workspace root pyproject.toml — inherited by all packages):

[tool.ruff]
line-length = 88
target-version = "py314"

[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "RUF"]

Philosophy: catch real bugs, enforce consistent formatting, don't fight scientists over naming or style. Dropped stylistic rules (N, SIM, C4, PIE, PT) that add noise without catching bugs.

uv run ty check packages/canvod-readers/src/canvod/readers/
uv run ty check canvodpy/src/canvodpy/

Configured per-package in pyproject.toml:

[tool.ty]
python = "3.14"

Supporting Tools

All common tasks are single commands:

just test             # Run the full test suite
just check            # Lint + format + type-check
just hooks            # Install pre-commit hooks
just docs             # Build and serve documentation locally
just config-init      # Initialize YAML config from templates
just config-validate  # Validate config files
just --list           # Show all available commands
uv run pytest                        # All tests
uv run pytest --cov=canvod           # With coverage
uv run pytest -m "not integration"   # Skip integration tests
uv run pytest packages/canvod-readers/tests/

Integration tests are marked @pytest.mark.integration and excluded from the default run.

just hooks    # Install hooks (run once after clone)

Configured in .pre-commit-config.yaml:

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    hooks:
      - id: ruff-check
        args: [--fix]
        stages: [pre-commit]
      - id: ruff-format
        stages: [pre-commit]
  - repo: https://github.com/astral-sh/uv-pre-commit
    hooks:
      - id: uv-lock
        stages: [pre-commit]
  - repo: https://github.com/pre-commit/pre-commit-hooks
    hooks:
      - id: trailing-whitespace
      - id: check-added-large-files
      - id: detect-private-key
      - id: end-of-file-fixer
  - repo: https://github.com/commitizen-tools/commitizen
    hooks:
      - id: commitizen
        stages: [commit-msg]

Hooks run on every git commitruff, uv-lock, and file hygiene checks run at the pre-commit stage; commitizen validates the commit message at commit-msg. Failures block the commit.


Tool Comparison

Task Traditional stack canVODpy
Package management pip uv
Virtual environments venv / virtualenv uv (built-in)
Linting flake8 + pylint ruff
Formatting black + isort ruff
Type checking mypy ty
Building setuptools uv_build
Publishing twine uv
Task runner make / tox just
Documentation Sphinx Zensical (MkDocs)

Quality & Security

canVODpy follows FAIR software principles and OpenSSF best practices:

  •   OpenSSF Best Practices


    Certified compliance with open source security best practices.

    Status: ✅ Passing level Badge: Project 12329

    Application Guide

  •   FAIR Software


    Compliance with the 5 FAIR software recommendations (findable, accessible, interoperable, reusable).

    Status: ⅘ met (PyPI pending v1.0) Automated: howfairis workflow runs on every push

    Implementation Summary

  •   OpenSSF Scorecard


    Automated security monitoring across 18+ best practice checks.

    Runs: Weekly + on every push to main Results: GitHub Security tab

    View Scorecard

  •   Security Policy


    Vulnerability reporting process with defined response timelines.

    Private reporting: GitHub Security Advisories Response time: 48 hours initial, 7-90 days fix

    Security Policy

Continuous Integration

All quality checks run automatically:

Workflow Runs On Purpose
test_platforms.yml Push, PR Multi-platform tests (Linux/macOS/Windows)
test_coverage.yml Push, PR Coverage tracking → Coveralls
code_quality.yml Push Linting, formatting, type checking
audit.yml PR, Weekly Integration tests with real data
fair-software.yml Push, PR FAIR compliance checks
scorecard.yml Weekly, Push to main Security best practices

All workflows must pass before merging to main.

See also: Security Policy · FAIR Compliance