# Enhancing Python Code Quality with Ruff and Pre-commit Hooks
URL: https://madhudadi.in/blog/posts/improve-python-code-quality-with-ruff-and-pre-commit
Published: 2026-06-26
Tags: python
Read time: 38 min
Difficulty: intermediate
> Learn Python code quality best practices with Ruff linting, Ruff formatting, import sorting, pyproject.toml configuration, type hints, pre-commit hooks, and CI checks.# Python Code Quality with Ruff, Formatting, Import Sorting, Type Hints, and pre-commit

## Quick Answer

Use Ruff to lint and format Python code.

```bash
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

```bash
python -m pip install ruff
```

If you use `pyproject.toml`:

```toml
[project.optional-dependencies]
dev = [
  "ruff>=0.5",
]
```

Run:

```bash
ruff --version
```

## 4. Run Ruff Checks

```bash
ruff check .
```

Automatically fix safe issues:

```bash
ruff check . --fix
```

Be careful with automatic fixes on large uncommitted changes. Review the diff.

## 5. Format With Ruff

```bash
ruff format .
```

Check formatting without changing files:

```bash
ruff format --check .
```

Use this in CI.

## 6. Configure Ruff In pyproject.toml

Basic configuration:

```toml
[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:

```python
from pathlib import Path
import pandas as pd
import os
from my_app.config import Settings
```

Ruff can sort them:

```python
import os
from pathlib import Path

import pandas as pd

from my_app.config import Settings
```

Run:

```bash
ruff check . --select I --fix
```

## 8. 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:

```python
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:

```python
def f(x):
    return x * 1.18
```

Better:

```python
def price_with_gst(base_price: float) -> float:
    return base_price * 1.18
```

Names should describe intent, not just data type.

## 10. Add Type Hints Where Useful

```python
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:

```python
try:
    value = int(raw)
except:
    value = 0
```

Better:

```python
try:
    value = int(raw)
except ValueError:
    value = 0
```

Catch the specific exception you expect.

## 12. Avoid Mutable Defaults

Weak:

```python
def add_item(item, items=[]):
    items.append(item)
    return items
```

Better:

```python
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items
```

Linters help catch this.

## 13. Add pre-commit

Install:

```bash
python -m pip install pre-commit
```

Create `.pre-commit-config.yaml`:

```yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.5.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format
```

Install hooks:

```bash
pre-commit install
```

Run on all files:

```bash
pre-commit run --all-files
```

## 14. Add Code Quality To CI

GitHub Actions example:

```yaml
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: pytest
```

CI 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.
