Skip to content

Ruff-Only "Golden Path" Development Setup

Overview

This repository uses Ruff as the single tool for Python code formatting and linting. This "golden path" approach ensures:

  • Single Source of Truth: All tool configurations in pyproject.toml
  • One Formatter: Ruff replaces Black, isort, and multiple linters
  • Pinned Versions: Deterministic builds with exact version control
  • Reproducibility: Identical results on local machines, containers, and CI
  • Simplicity: Fewer tools, faster feedback, less configuration

Why Ruff-Only?

Before: Multiple Tools

  • Black: Code formatting
  • isort: Import sorting
  • Flake8: Linting
  • Pylint: Additional linting
  • pycodestyle: Style checking
  • pydocstyle: Docstring checking

Problems: Tool conflicts, configuration drift, slow execution, version mismatches

After: Ruff Only

  • Ruff: All-in-one formatting + linting + import sorting
  • Speed: 10-100x faster than traditional tools
  • Compatibility: Drop-in replacement for Black + isort
  • Comprehensive: Implements 800+ linting rules

Quick Start

1. Install Dependencies

# Install all dependencies
make install

# Or manually:
pip install -r requirements.txt
pip install -r requirements-dev.txt
pip install -e .
pre-commit install

2. Format Your Code

# Format all code
make fmt

# Or use Ruff directly:
ruff format src/ tests/ scripts/
ruff check --fix --select I src/ tests/ scripts/  # Fix imports

3. Lint Your Code

# Check for linting issues
make lint

# Or use Ruff directly:
ruff check src/ tests/ scripts/

4. Run Pre-commit Hooks

# Run all pre-commit hooks (includes Ruff + MyPy + tests)
make pre-commit

# Or use pre-commit directly:
pre-commit run --all-files

Development Workflow

Before Committing

  1. Format your code: make fmt
  2. Fix linting issues: make lint
  3. Check types: make type
  4. Run tests: make test-unit
  5. Run pre-commit: make pre-commit

VS Code Integration

The repository is configured for automatic formatting on save:

  • Formatter: Ruff (replaces Black)
  • Import Organizer: Ruff (replaces isort)
  • Linter: Ruff (replaces Flake8/Pylint)

Settings in .vscode/settings.json:

{
    "[python]": {
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "source.fixAll.ruff": "explicit",
            "source.organizeImports.ruff": "explicit"
        }
    }
}

Pre-commit Hooks

Pre-commit automatically runs on every commit:

  1. Ruff Format: Formats code (replaces Black)
  2. Ruff Lint: Checks code quality (replaces Flake8/isort)
  3. MyPy: Type checking
  4. Pyupgrade: Syntax modernization (Python 3.12+)
  5. Bandit: Security checks
  6. Pre-commit hooks: File checks (YAML, TOML, JSON, trailing whitespace, etc.)
  7. Pytest: Unit tests (integration tests excluded for speed)

Configuration

pyproject.toml

All tool configuration lives in pyproject.toml:

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

[tool.ruff.format]
quote-style = "double"
indent-style = "space"

[tool.ruff.lint]
select = ["E", "F", "W", "C90", "I", ...]  # Comprehensive rule set
ignore = ["E501", ...]  # Pragmatic ignores

[tool.ruff.lint.isort]
known-first-party = ["portfolio_management"]
combine-as-imports = true

Version Pinning

All tools use pinned versions for reproducibility:

Pre-commit (.pre-commit-config.yaml):

  • Ruff: v0.8.0
  • MyPy: v1.11.2
  • Pyupgrade: v3.15.0
  • Pre-commit hooks: v5.0.0

Requirements (requirements-dev.txt):

  • ruff>=0.8.0
  • mypy>=1.11.0
  • pytest>=8.0.0
  • pre-commit>=4.0.0

CI/CD Integration

GitHub Actions workflow (.github/workflows/tests.yml):

- name: Set up Python
  uses: actions/setup-python@v5
  with:
    python-version: "3.12"  # Pinned to Python 3.12

- name: Run pytest suite
  run: pytest -m "not integration"  # Fast unit tests only

CI reproduces local behavior exactly:

  • Same Python version (3.12)
  • Same tool versions (pinned in pre-commit)
  • Same test selection (unit tests only)

Makefile Commands

The Makefile provides consistent commands across environments:

Command Description
make install Install all dependencies
make fmt Format code with Ruff
make lint Lint code with Ruff
make type Run type checking with MyPy
make test Run all tests
make test-unit Run only unit tests (fast)
make test-integration Run only integration tests
make pre-commit Run all pre-commit hooks
make clean Remove build artifacts

Ruff Features

Formatting (Replaces Black)

# Format files
ruff format src/

# Check formatting without changes
ruff format --check src/

Linting (Replaces Flake8, Pylint, etc.)

# Lint files
ruff check src/

# Auto-fix issues
ruff check --fix src/

# Show all violations
ruff check --output-format=full src/

Import Sorting (Replaces isort)

# Fix imports
ruff check --fix --select I src/

# Check import order
ruff check --select I src/

Migration from Black + isort

If you have existing code formatted with Black and isort:

  1. Ruff is Black-compatible: No reformatting needed
  2. Ruff import sorting: Compatible with isort's "black" profile
  3. One-time migration: Run make fmt to ensure consistency

Troubleshooting

Issue: Pre-commit hooks fail

Solution: Update pre-commit hooks

pre-commit clean
pre-commit install --install-hooks
pre-commit run --all-files

Issue: Ruff not found

Solution: Reinstall dev dependencies

pip install -r requirements-dev.txt

Issue: VS Code not using Ruff

Solution: Install Ruff extension and reload

  1. Install "Ruff" extension (charliermarsh.ruff)
  2. Reload VS Code
  3. Verify in settings: "editor.defaultFormatter": "charliermarsh.ruff"

Issue: Different results locally vs CI

Verify versions match:

# Local
ruff --version
mypy --version
python --version

# CI logs
# Check GitHub Actions output for version mismatches

Best Practices

  1. Always run make fmt before committing
  2. Use make pre-commit to verify everything passes
  3. Don't modify .pre-commit-config.yaml without updating docs
  4. Pin new tool versions explicitly
  5. Keep pyproject.toml as single source of truth

Resources

Support

For issues or questions:

  1. Check this documentation
  2. Review pyproject.toml for configuration
  3. Check .pre-commit-config.yaml for hook versions
  4. Consult Memory Bank (memory-bank/techContext.md)