๐งญ Tool Comparison โ CI/CD Recommendations
!!! abstract "Document Purpose" This document summarizes recommended tooling for FastAPI projects using UV, covering linting, formatting, type checking, testing, and security scanning. The goal is a pragmatic stack that works well locally (fast hooks) and in CI (strict checks).
โก Quick Recommendations
!!! success "Recommended Stack at a Glance"
| Category | Tool | Why? |
|----------|------|------|
| ๐ **Linting** | Ruff + isort | Blazing fast, comprehensive rules |
| ๐จ **Formatting** | Black or Ruff Format | Consistent, opinionated styling |
| ๐ **Type Checking** | Mypy (CI) + Pyright (IDE) | Best of both worlds |
| ๐งช **Testing** | pytest + Hypothesis | Industry standard + property testing |
| ๐ **Security** | Bandit + Semgrep + Safety + Trivy | Multi-layered protection |
๐ Linters โ Speed, Rules & Ergonomics
Comparing tools for code quality and style enforcement.
| Tool | Category | Pros | Cons | Score | Status |
|---|---|---|---|---|---|
| Ruff | Linter | โก Very fast (Rust-based) ๐ฆ Combines linting, fixing & formatting โ๏ธ Supports pyproject.toml |
โ ๏ธ Fewer deep analysis rules than Pylint for legacy code | 9/10 | โ Recommended |
| Flake8 | Linter | ๐ Mature ecosystem with many plugins ๐ bugbear, docstrings, etc. |
๐ Slower on large codebases ๐ Relies heavily on plugins |
7/10 | โ ๏ธ Specific contexts |
| Pylint | Linter | ๐ฌ Deep static analysis ๐ Code smells & complexity metrics |
๐ฃ๏ธ Verbose and slow by default โ๏ธ Requires extensive tuning |
7/10 | โ ๏ธ Audits/legacy code |
| Pyflakes | Linter | โก Fast execution ๐ฏ Detects undefined names/unused vars |
โ No stylistic checks (PEP8) | 6/10 | โ ๏ธ Component use only |
| Semgrep | SAST/Linter | โก Fast rule-based checks ๐ Security policy enforcement |
๐ More SAST-oriented โ ๏ธ May overlap with other tools |
8/10 | โ Security policies |
๐ก Why Choose Ruff?
!!! tip "Ruff: The Pragmatic Default" Ruff's speed and wide coverage make it ideal for:
- โ
Pre-commit hooks with instant feedback
- โ
Large codebases requiring fast linting
- โ
Teams wanting unified tooling
**Use Pylint only when you need deep, opinionated code audits.**
๐จ Formatters โ Speed, Configurability & Adoption
Ensuring consistent code style across your project.
| Tool | Category | Pros | Cons | Score | Status |
|---|---|---|---|---|---|
| Black | Formatter | ๐ฏ Opinionated & stable ๐ Widely adopted ๐ Small, consistent diffs |
โ๏ธ Limited customization | 9/10 | โ Recommended |
| Ruff Format | Formatter | โก Very fast & lightweight ๐ Integrates with Ruff toolchain |
๐ง Still evolving feature set | 9/10 | โ Great alternative |
| autopep8 | Formatter | ๐ PEP8-focused fixes โ๏ธ Configurable |
๐คท Less opinionated ๐ Larger diffs |
6/10 | โ ๏ธ Legacy use |
| YAPF | Formatter | โ๏ธ Highly configurable | ๐ Less adoption โ ๏ธ Results vary across versions |
6/10 | โ ๏ธ Not recommended |
| isort | Import Sorter | ๐ Industry standard ๐ค Black-compatible |
๐ฆ Imports only (not full formatter) | 8/10 | โ Use alongside |
๐ฏ Recommended Combination
!!! success "Winning Formula" Black (or Ruff Format) + isort
- Black/Ruff Format provides stable, opinionated formatting
- isort manages import organization
- Ruff can consolidate both if you want a single fast binary
=== "Option A: Classic"
yaml
# .pre-commit-config.yaml
- repo: https://github.com/psf/black
hooks:
- id: black
- repo: https://github.com/pycqa/isort
hooks:
- id: isort
=== "Option B: Unified"
yaml
# .pre-commit-config.yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
hooks:
- id: ruff
- id: ruff-format
- repo: https://github.com/pycqa/isort
hooks:
- id: isort
๐ Type Checkers โ Precision, Speed & IDE Integration
Static type checking for Python codebases.
| Tool | Category | Pros | Cons | Score | Status |
|---|---|---|---|---|---|
| Mypy | Static Type Checker | ๐ Reference implementation ๐ Strict checks available ๐ Plugin support (SQLModel, FastAPI) |
๐ Can be slower ๐ Configuration learning curve |
9/10 | โ CI-focused |
| Pyright | Static Type Checker | โก Very fast ๐ป Excellent editor integration (Pylance) ๐ฏ Great developer experience |
โ ๏ธ Less strict by default vs Mypy | 8/10 | โ IDE-focused |
| Pyre | Static Type Checker | โก Fast & scalable ๐ฌ Advanced analysis (Pysa) |
๐ข Less common outside Meta โ๏ธ Heavier setup |
7/10 | โ ๏ธ Large codebases |
| Pytype | Static Type Checker | ๐ Good inference for migrations | ๐ Less mainstream adoption | 7/10 | โ ๏ธ Alternative |
| Typeguard | Runtime Checker | ๐งช Runtime validation in tests | โ ๏ธ Runtime overhead โ Not for production |
7/10 | โ ๏ธ Test-only |
๐ฏ Recommended Strategy
!!! tip "Best of Both Worlds" Mypy in CI (strict mode) + Pyright for IDE (developer feedback)
This combination provides:
- โ
Strict enforcement in CI pipeline
- โ
Fast, real-time feedback during development
- โ
Best tooling integration for both contexts
Configuration Example:
# pyproject.toml
[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
๐งช Testing Frameworks โ Ease of Use, Plugins & Assertions
Building robust test suites for your application.
| Tool | Category | Pros | Cons | Score | Status |
|---|---|---|---|---|---|
| pytest | Framework | โจ Simple syntax with assert introspection ๐ Modular fixtures ๐ฏ Vast plugin ecosystem ๐ Parametrized tests |
๐ Learning curve for advanced fixtures | 10/10 | โ Recommended |
| unittest | Framework (stdlib) | ๐ฆ Built into Python ๐ Stable & mature ๐ค unittest.mock integration |
๐ Verbose syntax (assertEqual, etc.) ๐ Less ergonomic |
7/10 | โ ๏ธ Compatibility use |
| nose2 | Framework | ๐ Easy plugins ๐ Test discovery |
๐ Less active development ๐ฅ Smaller community |
6/10 | โ ๏ธ Not recommended |
| Hypothesis | Property Testing | ๐ฒ Generates random/priority tests ๐ Finds edge cases ๐งฎ Great for algorithms |
๐ค Different testing approach ๐ Requires different test design |
9/10 | โ Complementary |
| Robot Framework | Acceptance/RPA | ๐ค Robot syntax ๐ Multi-language support ๐ฏ High-level tests & RPA |
โ ๏ธ Overkill for simple API projects ๐ฏ Acceptance test focus |
6/10 | โ ๏ธ Specific use case |
๐ฏ Recommended Testing Stack
!!! success "Winning Combination" pytest as the foundation + Hypothesis for property testing
**Why pytest?**
- โ
Industry standard with massive adoption
- โ
Rich plugin ecosystem (coverage, markers, fixtures)
- โ
Excellent ergonomics and readability
**When to add Hypothesis?**
- โ
Parsers and data transformation logic
- โ
Algorithm implementations
- โ
Complex business rules
- โ
Edge case discovery
Example Usage:
=== "pytest Basic"
python
# test_api.py
def test_user_creation(client):
response = client.post("/users", json={"name": "Alice"})
assert response.status_code == 201
assert response.json()["name"] == "Alice"
=== "pytest + Fixtures" ```python # conftest.py @pytest.fixture def client(): return TestClient(app)
# test_api.py
def test_user_creation(client):
response = client.post("/users", json={"name": "Alice"})
assert response.status_code == 201
```
=== "pytest + Hypothesis" ```python from hypothesis import given from hypothesis import strategies as st
@given(st.text(min_size=1, max_size=100))
def test_username_validation(username):
result = validate_username(username)
assert isinstance(result, bool)
```
๐ Security Scanners โ Vulnerability Detection & False Positives
Multi-layered security scanning for applications and dependencies.
| Tool | Category | Pros | Cons | Score | Status |
|---|---|---|---|---|---|
| Bandit | Static Code Security | ๐ AST analysis โ ๏ธ Detects vulnerable patterns ๐ Python-specific (shell injection, unsafe eval) |
โ ๏ธ False positives possible โ๏ธ Rule tuning required |
8/10 | โ Recommended |
| Safety | SCA (Dependencies) | ๐ Known vulnerability detection ๐ Vulnerability database โจ Simple to use |
๐ฐ Advanced features paid (PyUp) ๐ฆ Limited to dependencies |
8/10 | โ Recommended |
| Trivy | Container/Image | ๐ณ Scans images & OS packages โก Fast & comprehensive ๐ Open source (Aqua) |
๐๏ธ Requires built image artifact | 9/10 | โ Recommended |
| Semgrep | SAST (Policy) | ๐ฏ Flexible rule engine ๐ Code-like rules ๐ Reusable patterns ๐ Low false positives |
๐ฐ Advanced features paid (Pro) โ๏ธ Requires tuning |
8/10 | โ Recommended |
| Snyk | SCA + Platform | ๐ SCA, SAST, container, IaC ๐ง Remediation guidance ๐ GitHub/GitLab integration ๐ UI reporting |
๐ฐ Paid (free tier limited) ๐ผ Enterprise features costly |
9/10 | โ Enterprise/org |
๐ก๏ธ Defense in Depth Strategy
!!! warning "Security Requires Multiple Layers" No single tool catches everything. Build a comprehensive security strategy:
=== "Code Analysis" Static Application Security Testing (SAST)
- โ
**Bandit** - Python-specific security issues
- โ
**Semgrep** - Custom security policies
```yaml
# .github/workflows/security.yml
- name: Run Bandit
run: bandit -r src/ -f json -o bandit-report.json
- name: Run Semgrep
run: semgrep --config auto src/
```
=== "Dependency Analysis" Software Composition Analysis (SCA)
- โ
**Safety** - Quick checks (open source)
- โ
**Snyk** - Enterprise reporting & remediation
```yaml
- name: Check dependencies
run: safety check --json
- name: Snyk test
run: snyk test --severity-threshold=high
```
=== "Container Security" Image & Runtime Scanning
- โ
**Trivy** - Container image vulnerabilities
```yaml
- name: Build image
run: docker build -t myapp:latest .
- name: Scan with Trivy
run: trivy image myapp:latest
```
๐ฏ Recommended Security Stack
!!! success "Comprehensive Coverage" Bandit + Semgrep (SAST) + Safety/Snyk (SCA) + Trivy (Containers)
This combination covers:
- ๐ Static code vulnerabilities
- ๐ฆ Dependency vulnerabilities
- ๐ณ Container security
- ๐ Security policy enforcement
โ Pragmatic Stack Recommendation
๐ Local Development & Pre-commit
!!! tip "Fast Feedback Loop" Keep local hooks lightweight for developer productivity:
# .pre-commit-config.yaml
repos:
# Formatting & Linting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
# Import sorting
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
args: [--atomic]
# Type checking (optional - can be slow)
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.0
hooks:
- id: mypy
args: [--ignore-missing-imports]
# Quick security checks
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
hooks:
- id: bandit
args: [-c, pyproject.toml]
Local Tools:
- โก Ruff (lint + format)
- ๐ฆ isort (imports)
- ๐ Mypy/Pyright (type checking)
- ๐งช pytest + Hypothesis (testing)
- ๐ Bandit + Semgrep (quick security)
- ๐ Safety (dependency scan)
โ๏ธ CI Pipeline Jobs
!!! info "Comprehensive CI Checks" Run parallel jobs for speed:
# .github/workflows/ci.yml
name: CI Pipeline
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv sync
- run: uv run ruff check .
- run: uv run ruff format --check .
- run: uv run isort --check-only .
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv sync
- run: uv run mypy src/
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv sync
- run: uv run pytest --cov --cov-report=xml
- uses: codecov/codecov-action@v3
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv sync
- run: uv run bandit -r src/
- run: uv run semgrep --config auto src/
- run: uv run safety check
security-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t app:${{ github.sha }} .
- name: Scan with Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: app:${{ github.sha }}
format: sarif
output: trivy-results.sarif
CI Jobs:
- ๐ Lint - Ruff check + format check + isort check
- ๐ Type Check - Mypy (strict mode) or Pyright
- ๐งช Tests - pytest with coverage
- ๐ Security - Bandit + Semgrep + Safety
- ๐ณ Image Security - Trivy scan on Docker images
๐ CD/Release Pipeline
!!! success "Production-Ready Releases" Additional checks before deployment:
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
security-final:
runs-on: ubuntu-latest
steps:
- name: Final Snyk scan
run: snyk test --severity-threshold=critical
- name: Final Trivy scan
run: trivy image app:${{ github.ref_name }}
publish:
needs: security-final
runs-on: ubuntu-latest
steps:
- run: uv build
- run: uv publish
๐ก Detailed Recommendations & Adoption Tips
๐ Start Small & Iterate
!!! tip "Progressive Adoption Strategy"
**Phase 1: Foundation (Week 1)**
1. โ
Set up Ruff + Black + isort in pre-commit โ fast corrections
2. โ
Add basic pytest tests
3. โ
Configure pyproject.toml
**Phase 2: Quality Gates (Week 2-3)**
1. โ
Add Mypy to CI with `--ignore-missing-imports`
2. โ
Gradually increase strictness
3. โ
Add coverage requirements
**Phase 3: Security (Week 3-4)**
1. โ
Integrate Bandit + Safety
2. โ
Add Semgrep rules
3. โ
Set up Trivy for containers
๐ง Tool Complementarity
!!! success "Use Multiple Tools in Harmony" Each tool catches different issue classes:
- ๐ **Ruff** - Quick fixes & common issues
- ๐ **Mypy** - Type safety & contracts
- ๐ **Semgrep** - Security policies & patterns
- ๐ฆ **Safety** - Dependency vulnerabilities
- ๐ณ **Trivy** - Container security
**Don't replace, complement!**
โก CI Performance Optimization
!!! tip "Speed Up Your Pipeline"
**Caching Strategy:**
```yaml
- uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- uses: actions/cache@v4
with:
path: |
~/.cache/pip
~/.cache/pre-commit
key: ${{ runner.os }}-cache-${{ hashFiles('**/uv.lock') }}
```
**Parallelization:**
- โ
Run lint, type-check, test, and security jobs in parallel
- โ
Use matrix strategies for multi-version testing
- โ
Cache UV dependencies and pre-commit environments
๐ Security & False Positives
!!! warning "Managing Security Tool Noise"
**Configuration Best Practices:**
```toml
# pyproject.toml
[tool.bandit]
exclude_dirs = ["tests", "migrations"]
skips = ["B101"] # Skip assert warnings in tests
[tool.semgrep]
paths.exclude = [
"tests/",
"*/migrations/",
]
```
**Progressive Refinement:**
1. โ
Start with default rules
2. โ
Create baseline of existing issues
3. โ
Add suppressions for false positives
4. โ
Document why suppressions exist
5. โ
Use Snyk/Safety Pro for prioritized remediation
๐จโ๐ป Developer Workflow Optimization
!!! tip "Balance Speed and Quality"
**Local (Fast):**
- โก Ruff `--fix` (instant)
- โก isort `--atomic` (fast)
- โก Quick formatting checks
**CI (Comprehensive):**
- ๐ Full Bandit scan
- ๐ณ Trivy image scan
- ๐ Mypy strict mode
- ๐ Full test suite with coverage
๐ Official Resources & Documentation
๐ Linting & Formatting
- Ruff: docs.astral.sh/ruff | GitHub
- Black: black.readthedocs.io | GitHub
- Flake8: flake8.pycqa.org
- Pylint: pylint.pycqa.org
- isort: pycqa.github.io/isort
๐ Type Checking
- Mypy: mypy-lang.org
- Pyright: GitHub | Pylance: VSCode extension
- Pyre: pyre-check.org
- Pytype: google.github.io/pytype
๐งช Testing
- pytest: pytest.org
- Hypothesis: hypothesis.readthedocs.io
- unittest: Python docs
๐ Security
- Bandit: bandit.readthedocs.io
- Safety: safetycli.com (PyUp)
- Snyk: snyk.io
- Trivy: trivy.dev
- Semgrep: semgrep.dev
๐ Conclusion
!!! success "Modern CI/CD Pipeline for FastAPI + UV"
**Recommended Stack:**
=== "Code Quality"
- ๐ **Ruff** (lint + format) or **Black**
- ๐ฆ **isort** (import sorting)
- ๐ **Mypy** (CI) + **Pyright** (IDE)
=== "Testing"
- ๐งช **pytest** (foundation)
- ๐ฒ **Hypothesis** (property testing)
- ๐ Coverage reporting
=== "Security"
- ๐ **Bandit + Semgrep** (SAST)
- ๐ฆ **Safety/Snyk** (SCA)
- ๐ณ **Trivy** (containers)
This combination provides:
โ
**Fast local development** with instant feedback
โ
**Comprehensive CI checks** catching issues early
โ
**Multi-layered security** protecting production
โ
**Developer-friendly** workflow with minimal friction
Ready to implement? Start with Phase 1 and iterate! ๐