DEV Community

Ankit Kumar
Ankit Kumar

Posted on

Integrate Ruff into Your Python Application and CI Pipeline: Step-by-Step Guide with Benchmarks

🧠 1. What is Ruff and Why Use It

Ruff is a fast, all-in-one Python linter, formatter, and import sorter written in Rust.
It replaces multiple tools like Flake8, isort, Black, and pyupgrade, drastically speeding up development and CI pipelines.

βš™οΈ Key Benefits

Feature Ruff Advantage
πŸš€ Speed 10–100Γ— faster than Flake8 or Pylint
🧰 All-in-one Linting + Formatting + Import Sorting
βš™οΈ Unified config Simple setup via pyproject.toml
πŸ’‘ Auto-fix Many issues can be fixed automatically
πŸ”§ CI-friendly Supports GitHub annotations

🧱 2. Create a Lightweight Example Application

Let’s create a simple Python app: a small To-Do manager.

πŸ—‚οΈ Project structure

todo_app/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ main.py
β”‚   └── utils.py
β”œβ”€β”€ tests/
β”‚   └── test_main.py
β”œβ”€β”€ pyproject.toml
β”œβ”€β”€ requirements.txt
└── .github/
    └── workflows/
        └── lint.yml
Enter fullscreen mode Exit fullscreen mode

🧰 3. Build the Example App

app/main.py

from app.utils import add_task, list_tasks

def main():
    print("Welcome to the To-Do App")
    add_task("Learn Ruff")
    add_task("Integrate Ruff in CI")
    print("Your Tasks:")
    for task in list_tasks():
        print(f"- {task}")

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

app/utils.py

tasks = []

def add_task(task: str):
    """Add a task to the list."""
    if not task:
        raise ValueError("Task cannot be empty")
    tasks.append(task)

def list_tasks():
    """Return all tasks."""
    return tasks
Enter fullscreen mode Exit fullscreen mode

tests/test_main.py

from app.utils import add_task, list_tasks

def test_add_task():
    add_task("Task 1")
    assert "Task 1" in list_tasks()
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ 4. Install Ruff

pip install ruff
Enter fullscreen mode Exit fullscreen mode

Verify:

ruff --version
Enter fullscreen mode Exit fullscreen mode

βš™οΈ 5. Configure Ruff with pyproject.toml

Here’s a well-commented configuration file with real-world defaults and examples.

pyproject.toml

[tool.ruff]
# Maximum line length (similar to Black’s default)
line-length = 88

# Specify Python version for compatibility
target-version = "py311"

# Select rulesets to enforce
# Common rule groups:
#   E/F = Pycodestyle (errors & warnings)
#   W = general warnings
#   I = import sorting
#   UP = pyupgrade rules (modernize code)
#   N = naming conventions
select = ["E", "F", "W", "I", "UP"]

# Ignore specific rule codes if desired
ignore = [
    "E501",  # ignore line length errors (if you rely on Black)
]

# Exclude certain paths (like virtualenvs or migrations)
exclude = ["venv", "build", "__pycache__", "migrations"]

# Show fixes when applying --fix
show-fixes = true

# Respect .gitignore patterns
respect-gitignore = true

# Auto-detect per-file ignores if necessary
per-file-ignores = { "tests/test_*.py" = ["S101"] }

# Enable incremental mode (optional, speeds up re-runs)
cache-dir = ".ruff_cache"

[tool.ruff.lint.isort]
# Sort imports intelligently
known-first-party = ["app"]
combine-as-imports = true
Enter fullscreen mode Exit fullscreen mode

🧩 6. Useful Ruff Commands

Here’s a table of common Ruff commands with explanations and when to use them:

Command Description Use Case
ruff check . Run all lint checks βœ… Recommended default
ruff check . --fix Auto-fix lint errors Use locally/pre-commit
ruff format . Format all Python files Code beautification
ruff format --check . Check if code is properly formatted Use in CI
ruff rule <CODE> Get details for a specific rule (e.g., ruff rule E501) Learn rules
ruff --explain <CODE> Explain why a rule triggered Debugging
ruff --help Show CLI options General help

Recommended CI Command:

ruff check .
It ensures linting consistency, and when combined with ruff format --check ., it gives both lint + format verification without auto-fixing in CI.


🧰 7. (Optional) Pre-commit Hook Setup

Create .pre-commit-config.yaml:

repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.6.15
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format
Enter fullscreen mode Exit fullscreen mode

Install:

pip install pre-commit
pre-commit install
Enter fullscreen mode Exit fullscreen mode

Now, Ruff runs automatically before every git commit.


🧩 8. GitHub Actions CI Integration

Let’s integrate Ruff into a lightweight GitHub Actions pipeline.

.github/workflows/lint.yml

name: Ruff Linting CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  lint:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install Ruff
        run: pip install ruff

      # πŸ”Ή Recommended: lint the code (no fixes)
      - name: Run Ruff Linter
        run: ruff check . --output-format=github

      # πŸ”Ή Optional: Check formatting
      - name: Check Ruff Formatting
        run: ruff format --check .
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Why --output-format=github?
This format makes lint results appear inline as annotations on your PR.


⚑ 9. Run Everything Locally

Try these locally:

ruff check .        # Lint check
ruff check . --fix  # Auto-fix issues
ruff format .       # Format code
pytest              # Run tests
Enter fullscreen mode Exit fullscreen mode

πŸ“Š 10. Benchmark (Optional)

Here’s an example of how fast Ruff runs compared to traditional linters.
Benchmark


🧩 11. Summary β€” End-to-End Flow

Stage Command Purpose
Local development ruff check . --fix Lint + auto-fix
ruff format . Format code
pytest Run tests
Pre-commit pre-commit run --all-files Run Ruff before commits
CI pipeline ruff check . & ruff format --check . Verify code cleanliness
Customization Edit [tool.ruff] in pyproject.toml Tailor lint rules

βœ… 12. Takeaways

  • Ruff = One tool replacing many (Flake8, isort, pyupgrade, partial Black)
  • Setup takes <5 minutes and improves local + CI performance drastically
  • Recommended pipeline commands:

    • ruff check .
    • ruff format --check .
  • Configuration is easy via pyproject.toml

  • Use pre-commit for best developer experience


Top comments (0)