Open-Source Wikis

/

Ruff

/

Features

/

Jupyter notebook support

astral-sh/ruff

Jupyter notebook support

Ruff can lint and format Jupyter notebook (.ipynb) files. This page covers how that works end-to-end.

What the user sees

ruff check notebook.ipynb
ruff format notebook.ipynb

Diagnostics report the cell index (e.g. cell 3:5:1) instead of just a line number. Fixes are applied in-place to the notebook JSON.

Pieces

  • crates/ruff_notebook/ — reads and writes .ipynb files using serde_json. Provides a Notebook type with cells, source mappings, and line offsets.
  • crates/ruff_linter/ — when given a .ipynb, the linter concatenates all code cells into one logical buffer (with delimiters), parses it, and runs all checkers. After lint, diagnostics are mapped back to (cell, line, column) via Notebook::source_map.
  • crates/ruff_python_formatter/ — formats each code cell independently and writes the result back into the notebook structure. Non-code cells (Markdown, raw) are passed through.

Source-map roundtrip

graph LR
    Ipynb[.ipynb file] --> Notebook[Notebook<br/>cells + sources]
    Notebook --> Concat[concatenated code buffer]
    Concat --> Parser[ruff_python_parser]
    Parser --> Linter[ruff_linter]
    Linter --> Diag[Diagnostics in concat coords]
    Diag --> Map[Source map<br/>concat → (cell, line)]
    Map --> Final[Diagnostics in cell coords]
    Final --> User

For the formatter, the same approach is used in reverse — each cell is formatted, then the cells are reassembled into the notebook JSON.

Caveats

  • Magic commands (%timeit, ?help, etc.) are tolerated but treated as opaque tokens. The parser recognizes them and the formatter leaves them alone.
  • Cell-level state is not tracked. Lint rules that look at the global module level see all cells flattened together, so something like "unused import in cell 1" only fires if the import is unused across the entire notebook.
  • A fix that would change cell boundaries is rejected. For instance, you can't autofix something into spanning two cells; that would change the notebook's cell structure.

Configuration

Notebook support is gated by globs. By default Ruff includes *.ipynb. To exclude:

[tool.ruff]
extend-exclude = ["*.ipynb"]

To control which rules apply only to notebooks, use per-file-ignores with the *.ipynb glob.

Where to start when extending

  • A specific rule misbehaves on notebooks: check that it uses the public source-map API rather than reaching into raw byte offsets.
  • Add new notebook-specific behavior: add helpers to crates/ruff_notebook/ and surface them from the linter or formatter.
  • Tests live alongside the linter/formatter, with .ipynb fixtures.

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

Jupyter notebook support – Ruff wiki | Factory