🧹 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:

  1. You edit your code
  2. You run git add .
  3. 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.