Python Linting Standard Operating Procedure (SOP)
Note: these articles are auto generated from my Obsidian notebook by Claude
This SOP establishes consistent linting practices for Python projects to ensure code quality, maintainability, and team efficiency.
Overview
Python linting involves automated code quality checks including:
- Code formatting (spacing, line breaks)
- Import organization
- Style guide compliance
- Common error detection
- Type checking (optional but recommended)
Tool Stack
Option 1: Modern Approach (Recommended for New Projects)
- Ruff: All-in-one linter and formatter (replaces Black, isort, Flake8)
- mypy or Pyright: Static type checking
Option 2: Traditional Approach (For Existing Projects)
- Black: Code formatting
- isort: Import sorting
- Flake8: Style guide enforcement
- mypy: Type checking (optional)
Configuration Standards
1. Line Length
- Standard: 100 characters
- Rationale: Balance between readability and modern displays
- Configuration: Set consistently across all tools
2. File Length
- Target: 300-500 lines per file
- Maximum: 500 lines (configurable based on project needs)
- Action: Refactor files exceeding limits into modules
3. Import Organization
- Order: Standard library → Third-party → Local imports
- Style: Alphabetical within groups
- Tool: isort with
profile = "black"or Ruff
Setup Instructions
For New Projects Using Ruff
1. Install Ruff:
pip install ruff
2. Create pyproject.toml:
[tool.ruff]
line-length = 100
target-version = "py310"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W"]
ignore = ["E501"] # Line length handled by formatter
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
3. Add to Makefile:
lint:
ruff check src/ --fix
ruff format src/
lint-check:
ruff check src/
ruff format --check src/
For Existing Projects Using Traditional Tools
1. Install tools:
pip install black isort flake8 flake8-length
2. Create .flake8:
[flake8]
max-line-length = 100
max-physical-line-length = 500
max-lines = 500
ignore =
# Black compatibility
E203, # Whitespace before ':'
W503, # Line break before binary operator
E704, # Multiple statements on one line
E501, # Line too long (handled by Black)
LLW405 # File length warnings (if allowing >100 lines)
exclude = venv,build,dist,.git,__pycache__,*.egg-info
3. Update pyproject.toml:
[tool.black]
line-length = 100
[tool.isort]
line_length = 100
profile = "black" # CRITICAL: Makes isort compatible with Black
4. Create/Update Makefile:
lint:
black src/
isort src/
flake8 src/
lint-check:
black --check src/
isort --check-only src/
flake8 src/
Pre-commit Setup
1. Install pre-commit:
pip install pre-commit
2. Create .pre-commit-config.yaml:
repos:
# For Ruff
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
# For traditional tools
- repo: https://github.com/psf/black
rev: 23.0.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
args: ["--profile", "black"]
3. Install hooks:
pre-commit install
CI/CD Integration
GitHub Actions Example
name: Lint and Test
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
- name: Run linting
run: make lint-check
- name: Run tests
run: make test
Publishing Workflow
Pre-publish Checklist
- ✅ Run
make lintto fix formatting - ✅ Run
make lint-checkto verify - ✅ Run
make testto ensure tests pass - ✅ Update CHANGELOG.md
- ✅ Commit all changes
- ✅ Run publish script
Common Publishing Issues and Solutions
1. "Working directory not clean"
- Solution: Commit or stash all changes
- Check:
git status
2. "Black wants to reformat files"
- Solution: Run
make lintbeforemake lint-check - Root cause: Formatter wasn't run
3. "isort and Black fighting"
- Solution: Add
profile = "black"to isort config - Verify: Both tools should be happy after one run
4. "File too long warnings (LLW405)"
- Solution: Either refactor large files OR add LLW405 to ignore list
- Decision: Based on project standards
Troubleshooting Guide
Issue: Linting passes locally but fails in CI
Causes:
- Different Python versions
- Missing dependencies
- Cache issues
Solution:
# Clear caches
rm -rf .pytest_cache __pycache__
# Reinstall in fresh environment
python -m venv fresh_env
source fresh_env/bin/activate
pip install -e ".[dev]"
make lint-check
Issue: Import order keeps changing
Cause: isort not configured for Black compatibility
Solution: Add profile = "black" to isort configuration
Issue: Line length conflicts
Cause: Different tools have different line length settings
Solution: Ensure all tools use same line-length (100 recommended)
Best Practices
-
Run linters before committing
- Use pre-commit hooks
- Include in PR checks
-
Fix linting incrementally
- Don't ignore all warnings at once
- Address root causes, not symptoms
-
Document exceptions
- If ignoring a rule, comment why
- Keep ignore list minimal
-
Regular updates
- Update linting tools quarterly
- Review and adjust rules annually
-
Team alignment
- Agree on standards as a team
- Document project-specific decisions
Quick Reference
Essential Commands
# Fix all formatting issues
make lint
# Check without modifying
make lint-check
# Run before publishing
make lint-check && make test
# Setup pre-commit
pre-commit install
pre-commit run --all-files
Configuration Files Priority
pyproject.toml- Primary configuration.flake8- Flake8 specific (can't use pyproject.toml)setup.cfg- Legacy, avoid if possible.pre-commit-config.yaml- Git hooks
Migration Path: Traditional → Ruff
Phase 1: Ensure current tools work together
- Fix Black/isort compatibility
- Resolve all linting errors
Phase 2: Install Ruff alongside
- Run both toolsets in parallel
- Compare outputs
Phase 3: Switch to Ruff
- Update configurations
- Update CI/CD
- Remove old tools
The Bottom Line
Consistent linting improves code quality and reduces review friction. Start strict and relax rules based on team needs. Automation is key - let tools handle formatting so developers can focus on logic.
Last Updated: 2024-12-25
Version: 1.0