Python Code Quality with Ruff, Formatting, Import Sorting, Type Hints, and pre-commit
Quick Answer
Use Ruff to lint and format Python code.
ruff check .
ruff format .Keep Ruff configuration in pyproject.toml, and add pre-commit hooks when the project becomes important.
Last verified: June 26, 2026.
Official Links
- Ruff docs: https://docs.astral.sh/ruff/
- Ruff rules: https://docs.astral.sh/ruff/rules/
- Ruff formatter: https://docs.astral.sh/ruff/formatter/
- pre-commit docs: https://pre-commit.com/
- Python typing docs: https://docs.python.org/3/library/typing.html
What You Will Learn
By the end, you should be able to:
- explain linting vs formatting
- install and run Ruff
- configure Ruff in
pyproject.toml - sort imports
- format code consistently
- add useful type hints
- set up pre-commit hooks
- run code quality checks in CI
1. What Is Code Quality?
Code quality means the project is easy to read, change, and review.
Good code quality includes:
- consistent formatting
- clean imports
- no unused variables
- clear names
- simple functions
- useful type hints
- predictable tooling
Tools do not replace judgment, but they remove repetitive review work.
2. Linting vs Formatting
Linting finds problems.
Examples:
- unused imports
- undefined names
- bad exception patterns
- overly complex code
Formatting rewrites code style.
Examples:
- line wrapping
- spacing
- quote normalization
- indentation
Ruff can do both.
3. Install Ruff
python -m pip install ruffIf you use pyproject.toml:
[project.optional-dependencies]
dev = [
"ruff>=0.5",
]Run:
ruff --version4. Run Ruff Checks
ruff check .Automatically fix safe issues:
ruff check . --fixBe careful with automatic fixes on large uncommitted changes. Review the diff.
5. Format With Ruff
ruff format .Check formatting without changing files:
ruff format --check .Use this in CI.
6. Configure Ruff In pyproject.toml
Basic configuration:
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "B", "UP"]
ignore = []Useful rule families:
| Code | Meaning |
|---|---|
E | pycodestyle errors |
F | Pyflakes |
I | import sorting |
B | bugbear-style warnings |
UP | modern Python upgrades |
Start small. Add stricter rules when the team is ready.
7. Import Sorting
Messy imports:
from pathlib import Path
import pandas as pd
import os
from my_app.config import SettingsRuff can sort them:
import os
from pathlib import Path
import pandas as pd
from my_app.config import SettingsRun:
ruff check . --select I --fix8. Keep Functions Small
Long functions are hard to test.
Instead of one function that reads a file, cleans data, calls an API, writes output, and prints a report, split responsibilities:
def read_orders(path):
...
def clean_orders(df):
...
def summarize_orders(df):
...
def write_report(summary, path):
...Small functions make tests and reviews easier.
9. Use Clear Names
Weak:
def f(x):
return x * 1.18Better:
def price_with_gst(base_price: float) -> float:
return base_price * 1.18Names should describe intent, not just data type.
10. Add Type Hints Where Useful
def normalize_slug(title: str) -> str:
return title.strip().lower().replace(" ", "-")Type hints are most useful on:
- public functions
- service functions
- parsing functions
- config objects
- functions used by many files
Do not let typing slow beginner learning too much. Add it where it clarifies.
11. Avoid Bare Except
Weak:
try:
value = int(raw)
except:
value = 0Better:
try:
value = int(raw)
except ValueError:
value = 0Catch the specific exception you expect.
12. Avoid Mutable Defaults
Weak:
def add_item(item, items=[]):
items.append(item)
return itemsBetter:
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return itemsLinters help catch this.
13. Add pre-commit
Install:
python -m pip install pre-commitCreate .pre-commit-config.yaml:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-formatInstall hooks:
pre-commit installRun on all files:
pre-commit run --all-files14. Add Code Quality To CI
GitHub Actions example:
name: Python quality
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install -e ".[dev]"
- run: ruff check .
- run: ruff format --check .
- run: pytestCI ensures checks run even if someone skips local hooks.
15. Code Quality Checklist
Before sharing a project, confirm:
- Ruff runs cleanly
- formatting is consistent
- imports are sorted
- functions are not doing too much
- names explain intent
- specific exceptions are caught
- public functions have useful type hints
- pre-commit is configured for important projects
- CI runs lint, format check, and tests
16. FAQ
Is Ruff a replacement for Black and isort?
Ruff can format code and sort imports, so many projects use Ruff instead of separate Black and isort tools.
Should beginners use Ruff?
Yes, but start with a small configuration. Do not enable every strict rule on day one.
Should I run ruff --fix automatically?
For small changes, yes. For large existing projects, run it carefully and review the diff.
Do type hints make Python faster?
Usually no. Type hints mainly help humans and tools understand your code.
Is pre-commit required?
No, but it is useful when a project has multiple contributors or repeated quality checks.
