Open-Source Wikis

/

Ruff

/

Features

/

Formatter

astral-sh/ruff

Formatter

End-to-end view of ruff format.

What the user sees

ruff format src/                  # rewrite files in place
ruff format --check src/          # exit non-zero if anything needs reformatting
ruff format --diff src/           # show what would change

The formatter aims to produce Black-compatible output by default, with a small list of intentional divergences documented in the formatter's CHANGELOG.md.

Pipeline

graph TD
    User[user runs ruff format]
    CLI[ruff format command<br/>crates/ruff/src/commands/format.rs]
    Workspace[ruff_workspace<br/>resolve format settings]
    Walker[file discovery]
    Files[Python files]
    Parser[ruff_python_parser]
    AST[Mod AST + tokens + trivia]
    Comments[Comments map<br/>leading / trailing / dangling]
    FormatTree[Format trait dispatch<br/>crates/ruff_python_formatter]
    IR[FormatElement IR<br/>crates/ruff_formatter]
    Printer[Printer with target line width]
    Output[Formatted source]

    User --> CLI
    CLI --> Workspace
    CLI --> Walker
    Walker --> Files
    Files --> Parser
    Parser --> AST
    AST --> Comments
    AST --> FormatTree
    Comments --> FormatTree
    FormatTree --> IR
    IR --> Printer
    Printer --> Output

What's handled where

Stage Where
Tokenization + parsing ruff_python_parser
Comment placement crates/ruff_python_formatter/src/comments/ — attaches each comment to a host node and a slot (leading / trailing / dangling)
Per-node formatting crates/ruff_python_formatter/src/{statement,expression,pattern}/ — one module per AST kind
IR engine crates/ruff_formatter — fork of rome_formatter with Format, format!, write!, groups, soft lines
Printing crates/ruff_formatter — width-aware printer that decides which groups break

Configuration knobs

ruff_workspace exposes [tool.ruff.format] settings:

  • line-length (defaults to 88, matching Black)
  • indent-width (defaults to 4)
  • quote-style (single, double, preserve)
  • indent-style (space, tab)
  • skip-magic-trailing-comma (mirrors Black's behavior)
  • line-ending (auto, lf, crlf, cr, native)
  • docstring-code-format, docstring-code-line-length (format code blocks within docstrings)

These are layered onto the PyFormatOptions consumed by the formatter.

Stability and idempotency

format(format(x)) == format(x) is required. Two harnesses enforce it:

  • cargo dev format-dev --stability-check runs the formatter against the curated corpus and asserts idempotency.
  • A fuzz target generates random valid Python and checks the same property.

A single non-idempotent rule is a release blocker.

Black compatibility

When a fixture diverges from Black's output, it's tracked in:

  • The formatter's CHANGELOG.md (intentional differences)
  • The Black-compatibility status table maintained in the docs
  • A snapshot test that pins the divergence

Promoting from "preview-only" to "stable" requires consensus from the formatter team.

Notebook support

Jupyter notebooks (.ipynb) are formatted cell-by-cell via ruff_notebook. Cell types other than code (markdown, raw) are passed through; code cells go through the same formatter pipeline.

Where to start when extending

  • A specific syntax doesn't format right: find the corresponding module under expression/ or statement/. The file names mirror the AST node kinds.
  • Comment placement bug: crates/ruff_python_formatter/src/comments/.
  • New configuration option: add it in crates/ruff_python_formatter/src/options.rs and propagate into ruff_workspace.
  • Performance: cargo bench -p ruff_benchmark exercises both lint and format paths.

For the crate-level view, see ruff_python_formatter.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Formatter – Ruff wiki | Factory