astral-sh/ruff
Linter
End-to-end view of how Ruff's linter turns a Python file into diagnostics.
What the user sees
ruff check src/For each file, Ruff reports issues like:
src/foo.py:3:1: F401 [*] `os` imported but unused
src/foo.py:8:5: E711 Comparison to `None` should be `is None`[*] means a fix is available. With --fix they're applied; with --unsafe-fixes even unsafe ones are.
End-to-end pipeline
graph TD
User[user runs ruff check]
CLI[ruff CLI<br/>crates/ruff]
Workspace[ruff_workspace<br/>resolve Settings]
Walker[ignore::WalkBuilder]
Files[file list]
Cache[ruff cache check]
Parser[ruff_python_parser]
Index[ruff_python_index]
Sem[ruff_python_semantic::SemanticModel]
Linter[ruff_linter::check_path]
Checkers[checkers/ast.rs<br/>checkers/tokens.rs<br/>checkers/physical_lines.rs<br/>checkers/logical_lines.rs<br/>checkers/imports.rs<br/>checkers/filesystem.rs<br/>checkers/noqa.rs]
Diag[Vec<Diagnostic>]
Fixer[ruff_linter::fix]
Printer[crates/ruff/src/printer.rs]
Output[stdout / file]
User --> CLI
CLI --> Workspace
CLI --> Walker
Walker --> Files
Files --> Cache
Cache --> Parser
Parser --> Index
Index --> Sem
Parser --> Linter
Sem --> Linter
Linter --> Checkers
Checkers --> Diag
Diag --> Fixer
Fixer --> Printer
Printer --> OutputPieces in detail
| Stage | Where | Notes |
|---|---|---|
| Argument parsing | crates/ruff/src/args.rs |
Clap-derived Args. |
| Settings resolution | crates/ruff_workspace/src/resolver.rs |
Walks for pyproject.toml / ruff.toml, applies CLI overrides. |
| File discovery | crates/ruff/src/resolve.rs |
Uses the ignore crate; respects .gitignore, .ignore, and Ruff's exclude. |
| Parallelism | rayon::par_iter |
One Rust-side concurrent task per file. |
| Caching | crates/ruff/src/cache.rs |
Per-package cache file under .ruff_cache/. |
| Parsing | ruff_python_parser |
Permissive, error-recovering. |
| Lint pipeline | ruff_linter |
Orchestrates checkers, manages SemanticModel. |
| Semantic model | ruff_python_semantic |
Built up by the AST checker as it walks. |
| Output | crates/ruff/src/printer.rs |
Multiple formats: text, concise, JSON, GitHub, SARIF, etc. |
Rule selection
--select and --ignore are parsed by ruff_linter::rule_selector. Selectors can be:
- A specific code (
F401) - A prefix (
F,E5) - A category (
ALL,EXTEND) - A plugin name (
flake8-bugbear)
Combined with select, extend-select, ignore, and extend-ignore from the configuration file. The end result is a RuleTable consulted by every checker.
Per-file overrides
per-file-ignores (and extend-per-file-ignores) attach to glob patterns. Before checking each file, the linter swaps in the matching RuleTable.
noqa
# noqa comments are parsed line-by-line by crates/ruff_linter/src/noqa.rs. Diagnostics emitted on a line whose noqa list covers the rule are suppressed at the end of the pipeline. Bare # noqa (no codes) suppresses all rules.
The noqa checker also flags unused/unknown directives, so codebases don't accumulate stale suppressions.
Output formats
Selected by --output-format. Implementations live in crates/ruff/src/printer.rs:
| Format | Use case |
|---|---|
text (default) |
Terminal display with color and snippets. |
concise |
One line per diagnostic. |
grouped |
Grouped by file. |
json |
Machine-readable (one JSON object). |
json-lines |
One JSON object per line. |
junit |
XML for test runners. |
github |
GitHub Actions annotations. |
gitlab |
GitLab Code Quality. |
sarif |
SARIF for security scanning tools. |
azure |
Azure Pipelines. |
pylint |
Pylint-compatible. |
Performance notes
- File reading and parsing dominate cold-cache runs.
- Hot caches reduce work to "stat, hash, compare key" per file.
rayonparallelism is per-file.- Most rules are O(AST size) at most; the AST checker dispatches by node kind so adding a rule rarely shows up as a hot spot.
Where to start when extending
- Add a rule: see
ruff_linter. - Tune file discovery:
crates/ruff/src/resolve.rs. - Add an output format:
crates/ruff/src/printer.rs+args.rs. - Add a configuration option:
ruff_workspace.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.