Filter concepts by levelShowing all levels.

Python · Formatting and linting

Formatting and linting

Black, isort, Ruff, Flake8, and pre-commit — verified against real, intentionally messy Python files in this environment

  • Ruffa fast, all-in-one linter and formatter, replacing much of Flake8
  • black + isortautomatic style and import-order enforcement, zero debate
  • pre-commitruns checks automatically before every commit is allowed

1.PEP 8 and code formatters (Black, isort)

PEP 8 is Python's official style guide — spacing, naming, line length. Black and isort are tools that automatically reformat code to follow style rules, so a team never has to debate spacing or import order by hand.

Key features

  • PEP 8 covers spacing, naming, line length (79 chars, teams often use 88-100), imports
  • black reformats a file in place, with almost no configuration options by design
  • isort sorts and groups import statements (stdlib, third-party, local) automatically
  • black --check reports whether files WOULD change, without writing — used in CI
  • A formatter has no opinion left to negotiate — running it twice makes no further changes

Formatters — what each one rewrites

Formatters — what each one rewrites
ToolRewrites
blackspacing, quote style, line breaks, trailing commas
isortimport statement order and grouping
ruff formatthe same as black, built into the same tool as ruff's linter
Two formatters, two separate jobs

messy.py

unsorted imports, ragged spacing

isort

sorts & groups imports only

black

spacing, quotes, line breaks

  1. messy.py — unsorted imports, ragged spacing
  2. isort — sorts & groups imports only
  3. black — spacing, quotes, line breaks

Command

python
black myfile.py
isort myfile.py
# or, check without writing (for CI):
black --check myfile.py

PEP 8 is the style guide; black and isort enforce it automatically — run them before every commit so style is never a manual decision or a review debate.

2.Ruff and Flake8

Ruff is a very fast linter (and formatter) that reimplements most of Flake8's rules plus many others, in one tool. Flake8 is the older, plugin-based linter it is increasingly replacing — still common in existing projects.

Key features

  • ruff check <file> lints unused imports/variables, unsorted imports, hundreds more rules
  • ruff's codes mirror Flake8's where they overlap (F401, E501) plus many Ruff-specific ones
  • flake8's codes come from separate plugins (pyflakes for F-codes, pycodestyle for E-codes)
  • ruff check --fix automatically applies fixes for rules that support it
  • Ruff is written in Rust and is measurably much faster than Flake8 on large codebases

Same bug, two linters' output shape

Same bug, two linters' output shape
IssueRuff codeFlake8 code
Unused importF401F401 (via pyflakes)
Unused variableF841F841 (via pyflakes)
Unsorted importsI001not detected (needs isort separately)
Missing whitespace around operatorE225E225 (via pycodestyle)
ruff check vs. flake8

ruff check

  • Written in Rust — measurably much faster
  • One tool: import sorting, unused code, hundreds of rules
  • Spacing is ruff format's job, not check's

flake8

  • Plugin-based — pyflakes (F-codes), pycodestyle (E-codes)
  • Needs a separate tool (isort) for import order
  • Catches spacing (E225) directly, in the same pass
  • ruff check
    • Written in Rust — measurably much faster
    • One tool: import sorting, unused code, hundreds of rules
    • Spacing is ruff format's job, not check's
  • flake8
    • Plugin-based — pyflakes (F-codes), pycodestyle (E-codes)
    • Needs a separate tool (isort) for import order
    • Catches spacing (E225) directly, in the same pass

Command

python
ruff check myfile.py         # lint
ruff check --fix myfile.py   # lint AND auto-fix
ruff format myfile.py        # format (Black-compatible)

Ruff is fast and all-in-one, covering most of Flake8's rules — but spacing is ruff format's job, not ruff check's.

3.Pre-commit

pre-commit is a framework that runs configured checks automatically every time someone runs git commit — the commit is blocked until every check passes, so bad formatting or an obvious lint error never reaches a shared branch.

Key features

  • .pre-commit-config.yaml declares which hooks (tools) run and on which files
  • pre-commit install registers a real git hook that runs automatically on every git commit
  • A failing hook blocks the commit — fix the issue (or let it auto-fix) and commit again
  • Hooks commonly include ruff, black, isort, and checks like "no trailing whitespace"
  • pre-commit run --all-files runs every hook against the whole repo, not just changed files

Command

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

# then:
pip install pre-commit
pre-commit install   # registers the git hook
git commit -m "..."  # hooks run automatically here

pre-commit runs configured checks on every git commit, blocking it until they pass — issues never reach a shared branch.

Remember

  • PEP 8 is the style guide; black/isort enforce it automatically, so style is never a manual debate.
  • black does not sort imports — that is isort's job, a separate step.
  • Ruff is fast and all-in-one but splits linting (ruff check) from formatting (ruff format).
  • pre-commit runs checks automatically on every git commit, catching issues before they reach a shared branch.

Pro tip

  • ruff check --fix only applies SAFE fixes by default — some fixes need --unsafe-fixes, opt-in.
  • Ruff's rule codes mirror Flake8's pyflakes/pycodestyle plugins where they overlap (F401, E501).
  • .pre-commit-config.yaml can run ruff, black, and isort together on every commit automatically.
  • black --check reports whether files WOULD change, without writing — the shape CI uses to enforce style.

Next up

  • Static analysis

Sources

  • Ruff — docs.astral.sh/ruff
  • PEP 8 — peps.python.org/pep-0008
  • Every tool run for real: ruff 0.16.0, black 26.5.1, isort 8.0.1, flake8 7.3.0 · checked 2026-08-21

Spotted a mistake on this page? Tell us.