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.ipynbDiagnostics 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.ipynbfiles usingserde_json. Provides aNotebooktype 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) viaNotebook::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 --> UserFor 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
.ipynbfixtures.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.