This document provides comprehensive information about using pre-commit hooks with Ruff for automatic Python code formatting in this repository.
- What is Pre-commit?
- Installation
- How It Works
- Usage Examples
- Common Ruff Errors
- Troubleshooting
- Best Practices
Pre-commit is a framework that manages Git hooks to run automated checks before each commit. In this repository, we use it to automatically format and lint Python code with Ruff.
Step 1: Install Required Tools
# Install Python and pip (if not already installed)
sudo apt update
sudo apt install python3 python3-pip -y
# Install pre-commit
pip install pre-commit
# Install ruff (optional, pre-commit will manage it automatically)
pip install ruffStep 2: Configure Pre-commit Hooks
From the repository root:
# Install the git hooks
pre-commit installNow, every time you commit, Ruff will automatically:
- ✅ Format your Python code
- ✅ Fix auto-fixable linting issues
⚠️ Stop the commit if there are issues that need manual attention
Step 1: Install Ruff Extension
- Open VS Code
- Go to Extensions (Ctrl+Shift+X)
- Search for "Ruff" by Astral Software
- Install the extension
Step 2: Configure VS Code Settings
Add to your .vscode/settings.json:
{
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
}
},
"ruff.lint.args": ["--config=pyproject.toml"],
"ruff.format.args": ["--config=pyproject.toml"]
}This will:
- Format your code automatically when you save
- Fix linting issues on save
- Organize imports automatically
Step 3: Install Pre-commit Hooks (Optional)
Even with VS Code, you can still install pre-commit hooks as a safety net:
pip install pre-commit
pre-commit installYou can run Ruff manually at any time:
# Format all Python files in src/
ruff format src/
# Check and fix linting issues
ruff check src/ --fix
# Check without fixing (dry-run)
ruff check src/
# Run on specific file
ruff format src/my_module/my_file.py
ruff check src/my_module/my_file.py --fixWhen you commit code, the pre-commit hook automatically runs:
- You run
git commit - Pre-commit intercepts the commit
- Ruff checks and formats all Python files in
src/ - If files are modified: commit is blocked → review changes → stage them → commit again
- If errors need manual fixing: commit is blocked → fix errors → stage fixes → commit again
- If everything is clean: commit succeeds immediately ✅
# You make changes and stage them
git add src/my_file.py
# You try to commit
git commit -m "Add new feature"
# Pre-commit runs automatically
# → Ruff formats your code
# → If changes were made, commit is BLOCKED
# Review the changes
git diff src/my_file.py
# If you agree with the changes, stage them
git add src/my_file.py
# Commit again
git commit -m "Add new feature"
# ✅ Success!Pre-commit will show specific errors (e.g., lines too long, naming conventions):
git commit -m "Add new feature"
# ⚠️ Ruff shows errors:
# E501 Line too long (120 > 100)
# N801 Class name should use CapWords
# Fix the errors in your editor
# Then stage and commit again
git add src/my_file.py
git commit -m "Add new feature"In rare emergencies, you can skip pre-commit:
git commit -m "Emergency fix" --no-verifyWhen your code is already properly formatted:
$ git add src/my_module/my_file.py
$ git commit -m "Add new feature"
ruff.....................................................................Passed
ruff-format..............................................................Passed
[jazzy-devel abc1234] Add new feature
1 file changed, 10 insertions(+)✅ Commit succeeds immediately!
When Ruff can automatically fix formatting issues:
$ git add src/my_module/my_file.py
$ git commit -m "Add new feature"
ruff.....................................................................Passed
ruff-format..............................................................Failed
- hook id: ruff-format
- files were modified by this hook
1 file reformatted
# ⚠️ Commit blocked! Files were auto-formattedWhat to do:
# Review the changes
$ git diff src/my_module/my_file.py
# If you agree with the formatting, stage the changes
$ git add src/my_module/my_file.py
# Commit again
$ git commit -m "Add new feature"
ruff.....................................................................Passed
ruff-format..............................................................Passed
[jazzy-devel abc1234] Add new feature
1 file changed, 10 insertions(+)✅ Commit succeeds!
When there are linting issues that need manual attention:
$ git add src/my_module/my_file.py
$ git commit -m "Add new feature"
ruff.....................................................................Failed
- hook id: ruff
- exit code: 1
src/my_module/my_file.py:10:101: E501 Line too long (120 > 100)
|
8 | def my_function():
9 | # This is a very long comment that exceeds the maximum line length of 100 characters and needs to be split
10 | very_long_variable_name = "This is a very long string that exceeds the maximum line length of 100 characters"
| ^^^^^^^^^^^^^^^^^^^^ E501
11 | return very_long_variable_name
|
src/my_module/my_file.py:15:7: N801 Class name `myClass` should use CapWords convention
|
13 |
14 | # Bad class name
15 | class myClass:
| ^^^^^^^ N801
16 | pass
|
Found 2 errors.
# ⚠️ Commit blocked! Manual fixes neededWhat to do:
# Fix the issues in your editor
# 1. Break the long line into multiple lines
# 2. Rename myClass to MyClass
# Stage the fixes
$ git add src/my_module/my_file.py
# Commit again
$ git commit -m "Add new feature"
ruff.....................................................................Passed
ruff-format..............................................................Passed
[jazzy-devel abc1234] Add new feature
1 file changed, 10 insertions(+)✅ Commit succeeds!
In rare emergencies, you can skip pre-commit hooks:
$ git commit -m "Emergency hotfix" --no-verify
[jazzy-devel abc1234] Emergency hotfix
1 file changed, 5 insertions(+)You can run pre-commit checks without committing:
# Run on all files
$ pre-commit run --all-files
# Run on specific files
$ pre-commit run --files src/my_module/my_file.py
# Run only the ruff hook
$ pre-commit run ruff --all-files
# Run only the ruff-format hook
$ pre-commit run ruff-format --all-filesError:
E501 Line too long (120 > 100)
Fix: Break long lines into multiple lines:
# Before
result = some_function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
# After
result = some_function(
arg1, arg2, arg3, arg4, arg5,
arg6, arg7, arg8, arg9, arg10
)Error:
N801 Class name `myClass` should use CapWords convention
Fix: Rename class to use CamelCase:
# Before
class myClass:
pass
# After
class MyClass:
passError:
E402 Module level import not at top of file
Fix: Move imports to the top of the file:
# Before
def my_function():
pass
import os # ❌ Import after code
# After
import os # ✅ Import at top
def my_function():
passError:
F401 [*] `os` imported but unused
Fix: Remove the unused import:
# Before
import os # ❌ Not used anywhere
import sys
# After
import sys # ✅ Only import what you useIf you need to temporarily disable pre-commit:
# Uninstall the hook (can be reinstalled later)
$ pre-commit uninstall
# Reinstall when ready
$ pre-commit installTo update to the latest version of Ruff:
$ pre-commit autoupdateThis will update the version in .pre-commit-config.yaml.
If you have the Ruff extension installed in VS Code, you'll see the same errors inline:
- Errors appear with red squiggly lines
- Hover over them to see the error message
- Use Quick Fix (Ctrl+.) to apply auto-fixes
- Format on save will run Ruff automatically
# Make sure it's installed
$ pre-commit install
# Verify it's configured
$ ls -la .git/hooks/pre-commit# Clean the cache
$ pre-commit clean
# Try again
$ pre-commit run --all-filesEdit pyproject.toml and add the rule to the ignore list:
[tool.ruff.lint]
ignore = [
"E501", # Ignore line length errors
]- Run pre-commit before pushing to avoid surprises in CI/CD
- Fix issues immediately rather than bypassing pre-commit
- Use
--all-filesperiodically to catch any issues in existing code - Keep hooks updated with
pre-commit autoupdate - Enable format-on-save in VS Code for instant feedback