astral-sh/ruff
ruff_linter
The linter engine — registry of rules, per-pass checkers, and the public check_path API. Source: crates/ruff_linter/.
Purpose
ruff_linter consumes a parsed Python file plus resolved settings and produces a list of Diagnostic values, optionally with attached Fixes. Every lint rule (~900 of them) lives in this crate.
Directory layout
crates/ruff_linter/src/
├── lib.rs
├── linter.rs # check_path entry point
├── linter/ # supporting helpers
├── registry.rs # Rule enum + categories
├── codes.rs # rule code → Rule mapping (single source of truth)
├── rule_selector.rs # parses --select / --ignore expressions
├── rule_redirects.rs # legacy code aliases
├── checkers/ # per-pass visitors
│ ├── ast.rs # the big AST visitor that drives most rules
│ ├── tokens.rs
│ ├── physical_lines.rs
│ ├── logical_lines.rs
│ ├── imports.rs
│ ├── filesystem.rs
│ └── noqa.rs
├── rules/ # 60 plugin folders, one per rule family
│ ├── pyflakes/
│ ├── pycodestyle/
│ ├── flake8_bugbear/
│ ├── pyupgrade/
│ ├── ruff/ # Ruff-native rules (RUF*)
│ └── …
├── fix/
├── docstrings/
├── importer/
├── settings/ # LinterSettings + per-rule sub-settings
├── message/
├── noqa.rs
├── package.rs
├── packaging.rs
├── pyproject_toml.rs
├── preview.rs
├── doc_lines.rs
├── line_width.rs
├── locator.rs
├── logging.rs
├── registry/
├── renamer.rs
├── snapshots/
├── comments/
├── cst/
└── fs.rsKey abstractions
| Type | File | Purpose |
|---|---|---|
Rule |
crates/ruff_linter/src/registry.rs |
The exhaustive enum of every rule. |
RuleCode |
crates/ruff_linter/src/codes.rs |
Mapping between user-facing codes and Rule. |
RuleSelector |
crates/ruff_linter/src/rule_selector.rs |
Parsed --select expression (E, E5, E501, ALL). |
LinterSettings |
crates/ruff_linter/src/settings/ |
Resolved per-file lint settings. |
Checker (AST) |
crates/ruff_linter/src/checkers/ast.rs |
The main visitor that walks the AST and dispatches rules. |
Diagnostic |
crates/ruff_diagnostics |
Emitted by rules; carries optional Fix. |
check_path |
crates/ruff_linter/src/linter.rs |
Public entry point used by ruff and ruff_wasm. |
How it runs (per file)
graph TD
Source[Python source]
Parser[ruff_python_parser]
Indexer[ruff_python_index]
Tokens[Token stream]
AST[Mod AST]
Source --> Parser
Parser --> AST
Parser --> Tokens
AST --> Indexer
Indexer --> Sem[SemanticModel]
AST --> AstChecker[checkers/ast.rs]
Tokens --> TokenChecker[checkers/tokens.rs]
Source --> PhysChecker[checkers/physical_lines.rs]
Tokens --> LogChecker[checkers/logical_lines.rs]
Indexer --> ImpChecker[checkers/imports.rs]
AstChecker --> Diag[Diagnostics + Fixes]
TokenChecker --> Diag
PhysChecker --> Diag
LogChecker --> Diag
ImpChecker --> Diag
AstChecker -.uses.-> SemThe AST checker is by far the largest. It implements Visitor over ruff_python_ast::Mod and, on each node, dispatches to every enabled rule that cares about that node kind. This is what lets Ruff run hundreds of rules in a single pass.
Rule plugin directories
The 60 directories under rules/ are one per upstream tool (or one per Ruff-native family):
airflow flake8_django flake8_pyi
copyright flake8_errmsg flake8_pytest_style
eradicate flake8_executable flake8_quotes
fastapi flake8_fixme flake8_raise
flake8_2020 flake8_future_annotations flake8_return
flake8_annotations flake8_gettext flake8_self
flake8_async flake8_implicit_str_concat flake8_simplify
flake8_bandit flake8_import_conventions flake8_slots
flake8_blind_except flake8_logging flake8_tidy_imports
flake8_boolean_trap flake8_logging_format flake8_todos
flake8_bugbear flake8_no_pep420 flake8_type_checking
flake8_builtins flake8_pie flake8_use_pathlib
flake8_commas flake8_print flynt
flake8_comprehensions isort mccabe
flake8_copyright pycodestyle pandas_vet
flake8_datetimez pydoclint pep8_naming
flake8_debugger pydocstyle perflint
pyflakes pygrep_hooks
pylint pyupgrade
refurb ruff
tryceratops numpy(One plugin per Flake8 ecosystem tool, plus a few first-party families like ruff/, numpy/, airflow/.)
Inside each plugin folder:
flake8_bugbear/
├── mod.rs # registration + helper functions
├── rules/ # one .rs file per rule (`B001.rs`, `B002.rs`, …)
└── snapshots/ # insta snapshotsRule code → struct mapping
crates/ruff_linter/src/codes.rs is the canonical mapping. Each rule has:
- A 1–4 character code prefix (e.g.
F,B,RUF) - A 3–4 digit number
- A struct that implements the rule (in
rules/<plugin>/rules/<name>.rs) - Doc comments rendered in the rule explainer
Rule selectors and presets
Users select rules with codes (F401, B, E5) or category names (ALL, EXTEND). The grammar is implemented in rule_selector.rs. Presets such as ALL are computed at compile time.
rule_redirects.rs keeps old codes pointing to their renamed targets so user configs don't break across versions.
Fixes and applicability
Rules attach a Fix to a diagnostic when an automatic correction is possible. The Applicability enum (Safe, Unsafe, DisplayOnly) determines whether --fix will actually apply it without --unsafe-fixes. Fix machinery lives in crates/ruff_linter/src/fix/.
Noqa
noqa.rs parses # noqa: F401, E501 comments and exposes APIs the AST checker uses to filter diagnostics. The noqa checker also flags unused/unknown directives.
Settings
LinterSettings is a large struct combining global toggles (line length, target version) and per-rule sub-settings (e.g. flake8_bugbear::Settings, pylint::Settings). It's built from ruff_workspace::Settings.
Adding a rule
- Pick a plugin directory (or, for new families, create one).
- Add a
RuleCodeincodes.rs. - Write
rules/<plugin>/rules/<rule_name>.rswith the visitor function and the diagnostic struct (with rich doc-comments). - Register the rule in the plugin's
mod.rs. - Add a fixture under
resources/test/fixtures/<plugin>/<rule>.py. - Add a snapshot test in the plugin module.
- Run
cargo dev generate-allto update schemas and docs.
For an end-to-end walkthrough, see features/linter.
Integration points
- Consumed by
ruffCLI,ruff_server, andruff_wasm. - Depends on
ruff_python_parser,ruff_python_ast,ruff_python_semantic,ruff_diagnostics,ruff_workspace.
Where to dig deeper
- The big visitor:
crates/ruff_linter/src/checkers/ast.rs. - Rule registration patterns:
crates/ruff_linter/src/codes.rsand anyrules/<plugin>/mod.rs. - Fix application:
crates/ruff_linter/src/fix/.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.