🧹 Want your code to be clean every single time you hit commit?
Tired of manually fixing linting errors or arguing over code style in PRs?
This setup is for you.
🤔 Why Use This Setup?
Whether you’re working alone or in a team, this setup helps you:
- ✅ Keep your code clean and consistent automatically
- ✅ Enforce formatting rules without remembering to run anything
- ✅ Avoid polluting
.gitignore
with local files like VS Code settings - ✅ Stay productive without annoying formatting distractions
📌 Use Cases:
You're contributing to a legacy or open-source codebase that doesn’t enforce linting yet — but you still want to follow high-quality standards just for your own changes.
You're part of a team, and not everyone uses the same dev tools. This lets you quietly enforce clean code locally without adding noise to the repo.
You're learning or mentoring, and want a low-effort way to keep Python code consistent and readable.
🛠️ Part 1: Install Required Tools
# Install these in your virtual environment
pip install ruff pre-commit
Why: These tools format your code and enforce coding standards automatically.
⚙️ Part 2: Create Project Configuration Files
✅ Step 1: Create Pre-commit Configuration
touch .pre-commit-config.yaml
Paste this into .pre-commit-config.yaml
:
exclude: '(^|/)(alembic|tests)/|(^|/)__init__\.py$'
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.10
hooks:
- id: ruff
args: [ --fix ]
stages: [pre-commit]
- id: ruff-format
stages: [pre-commit]
✅ Step 2: Configure Ruff Rules
touch pyproject.toml
Paste this into pyproject.toml
:
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
]
ignore = ["D203", "D212"]
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
[tool.ruff.lint.pydocstyle]
convention = "google"
🚫 Part 3: Exclude Files Locally (Without .gitignore
)
To keep your repository clean, we’ll exclude helper scripts and editor settings without adding them to .gitignore
.
# This keeps files ignored only on your machine
echo "pyproject.toml" >> .git/info/exclude
echo ".vscode/settings.json" >> .git/info/exclude
Why: These files are personal and environment-specific. You need them — your team doesn’t.
💻 Part 4: Configure VS Code
mkdir -p .vscode
touch .vscode/settings.json
Paste this into .vscode/settings.json
:
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "always",
"source.organizeImports.ruff": "always"
},
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
},
"ruff.format.preview": true,
"autoDocstring.docstringFormat": "google",
"autoDocstring.generateDocstringOnEnter": true
}
🔑 Part 5: Activate Pre-commit
# This creates a Git hook that makes pre-commit run automatically on every commit.
pre-commit install
✅ Confirmed: Automatic Formatting on Commit
Here’s how your workflow looks after setup:
- You edit your code
- You run
git add .
- You commit:
git commit -m "Your message"
Then pre-commit:
- Runs Ruff to check and fix your code
- If Ruff makes changes, the commit pauses
- You’ll need to
git add
the fixed files again - Then re-run
git commit
🧪 Bonus: Run Ruff Only on Your Changes with check_my_changes.sh
This helper script is a must-have when:
- You're working on a large codebase
- Ruff isn’t configured globally
- You only want to lint and fix your own feature branch changes
📄 check_my_changes.sh
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
echo "Getting changed Python files compared to dev branch..."
MODIFIED_FILES=$(git diff --name-only origin/dev...HEAD | grep '\.py$')
if [ -z "$MODIFIED_FILES" ]; then
echo "No Python files changed in your branch."
exit 0
fi
echo "============================================="
echo "Checking these files:"
echo "$MODIFIED_FILES"
echo "============================================="
echo "$MODIFIED_FILES" | xargs ruff check --fix
echo "============================================="
echo "Done! Your code is now cleaner."
echo "============================================="
💡 Use Case:
If the main repo doesn’t enforce linting yet (no Ruff config, no CI hooks), but you want your code to stay clean — this script lints only what you’ve touched, without you needing to run Ruff manually file by file.
🎯 Final Thoughts: Start Clean, Stay Clean
Code quality is not just for big teams or fancy open-source projects.
It starts with you.
Whether you're:
- Working solo
- Contributing to a chaotic legacy repo
- Just learning to write better Python
- Or collaborating in a fast-paced team...
This setup gives you a head start — without needing permission, without needing a fancy CI setup, and without adding clutter to your repo.
Let Ruff and Pre-commit do the heavy lifting, so you can focus on building features — not fixing quotes and spacing.
✨ Bonus: When your team sees how clean your PRs are, they might adopt this too. Be the change 😎
🗣️ Over to You:
Try this out and tell me how it worked! Got questions? Found a tweak that improved your workflow? Drop a comment — I’d love to learn from you too.