mrkeyoor.com_
Sat 19 Sept 06:40 UTC
PyPICLI & Toolingupdated 19 Sept 2026

ruff review

Ruff 0.16.4 is a compiled command-line linter and formatter for Python files and notebooks. Its built-in rule catalog reimplements checks associated with Pyflakes, pycodestyle, isort, pyupgrade, flake8-bugbear, Bandit, Pylint, and many other tools; `ruff format` handles Black-compatible formatting as a separate command. Configuration can cascade through a monorepo, the linter caches unchanged files, fixes are labeled safe or unsafe, and editor integrations use the Ruff server. Version 0.16.4 fixes crashes on Windows CPUs without POPCNT, reports duplicate keyword arguments and parameters declared `nonlocal`, improves notebook pull diagnostics, and aligns several syntax and rule cases with current Python behavior.

Verdict

Ruff 0.16.4 installed as 1 package using 1 MB in 0.5 seconds, imported in 0.04 seconds, and produced 0 audit findings in our sandbox. Pin it for linting, import rules, and formatting when its catalog covers the project, but keep a type checker and any unsupported plugin beside it.

We installed it

Lab card: what happened when we installed ruffScreenshot of ruff documentation
Install✓ · 0.5s1 package on disk · 1 MB
Importimport ruff in 0.04s · compiled extensions · requires Python >=3.7
Known vulns0(pip-audit)

Answers from our run

Does ruff install cleanly?

Yes. In a fresh container with an empty cache, pip install ruff finished in 0.5s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.

What does ruff need to run?

Python >=3.7, and a platform wheel with compiled extensions. In our run import ruff succeeded in 0.04s.

ruff or flake8: which should you use?

flake8: Keep it when a required third-party plugin has no corresponding Ruff rule family. Ruff 0.16.4 installed as 1 package using 1 MB in 0.5 seconds, imported in 0.04 seconds, and produced 0 audit findings in our sandbox.

When should you not use ruff?

An essential Flake8 plugin has no Ruff rule family. Ruff implements rules internally and does not load arbitrary Flake8 plugins.

API stability3/5The `check`, `format`, `rule`, and `config` commands, TOML section layout, rule codes, exit behavior, and editor server are established enough for routine automation. Ruff remains on 0.16.4, and each minor release can adjust syntax diagnostics, fix availability, default indicators, or formatter output. Preview features are explicitly opt-in, but stable rule changes can still affect a CI gate, so every integration should use the same pinned binary.
Docs5/5The official site gives each rule a page with failing and passing code, origin, options, and fix-safety information. Separate sections cover configuration discovery, settings, editor setup, formatter differences from Black, import sorting, preview mode, versioning, and migration from related tools. Release notes for 0.16.4 divide preview work, bug fixes, rule changes, server behavior, and platform corrections, making upgrade review practical.
Maintenance5/5Ruff 0.16.4 was released on August 20, 2026, and GitHub reports a push on August 26, 2026, 49,339 stars, 2,154 open issues and pull requests, and an unarchived repository. That patch repairs a CPU-specific Windows crash, changes parser diagnostics, improves notebook language-server behavior, and hardens internal AST and stack handling. The issue queue is large, but release and repository activity are both current.
Ecosystem5/5This batch records 77,677,334 weekly downloads, and GitHub shows 49,339 stars. Astral publishes a pre-commit integration, a GitHub Action, standalone installers, editor support, and packages through several distribution channels. More than 900 built-in rules cover many named Flake8 plugin families and adjacent tools. Consolidation stops at documented boundaries: external Flake8 plugins and type checkers remain separate.

Discussed on

  1. hnRuff: Python linter and code formatter written in Rust200 points
  2. hnAvoid unnecessary parser lookahead for operators3 points
  3. hnRuff: fast Python linter and code formatter, written in Rust3 points

Use it if

  • One pinned executable should cover common lint rules, import sorting, code upgrades, and formatting in local hooks and CI.
  • Existing lint latency is high enough that developers avoid running checks before a push.
  • A monorepo needs shared defaults with narrower configuration in individual Python projects.
  • Automatic changes must distinguish generally safe fixes from behavior-changing unsafe fixes.
Skip it if

Setup reality

We installed Ruff 0.16.4 in a fresh Python 3.12 Bookworm container in 0.5 seconds. The environment contained 1 package using 1 MB, and Ruff declares 0 direct dependencies with a Python 3.7 minimum. The wheel ships compiled .so files and does not include py.typed. pip-audit found 0 known vulnerabilities. import ruff completed in 0.04 seconds in our sandbox, though the supported product surface is the ruff executable rather than a documented Python library.

Ruff reads pyproject.toml, ruff.toml, or .ruff.toml. In pyproject, top-level settings live under [tool.ruff], linter settings under [tool.ruff.lint], and formatter settings under [tool.ruff.format]. Config discovery walks ancestors and can extend another file. A plain ruff check enables the documented default set, not every available rule. Inventory current Flake8 plugins and options before removing them, since unsupported plugins cannot be imported into Ruff.

Linting and formatting are two commands. ruff check --fix applies fixes classified as safe; --unsafe-fixes can change runtime meaning and needs a source review. Import sorting is ruff check --select I --fix, not part of ruff format. Pin 0.16.4 in project dependencies, pre-commit, editor settings, and CI together. Preview mode opts into unfinished rules and formatting behavior, so it should not arrive accidentally through one developer's editor.

Ruff writes .ruff_cache by default and respects normal cache controls, which matters in read-only or disposable CI workspaces. Begin a migration with the existing behavior and add rule families in reviewable batches. --add-noqa edits the tree and can hide too much if used as an automatic baseline. For machine consumption, choose an output format and use exit codes; importing the ruff package is not a substitute for its CLI contract.

Patterns

Pin Ruff and run both modes pin-and-run

uv add --dev ruff==0.16.4

uv run ruff check .
uv run ruff format .

Linting and formatting are separate commands. Pin the same 0.16.4 release in local, editor, hook, and CI environments.

Set target Python and lint families configure-project

[tool.ruff]
target-version = "py312"
line-length = 100

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I", "B", "UP"]

In `pyproject.toml`, lint settings belong under `[tool.ruff.lint]`. A `ruff.toml` file omits the `tool.ruff` prefix.

Show lint changes before applying them check-without-writing

ruff check --diff .
ruff check --fix .

The normal `--fix` path applies fixes Ruff classifies as safe. Review `--unsafe-fixes` separately because behavior can change.

Fail CI on formatter differences verify-formatting

ruff format --check --diff .

This checks formatting only. Run `ruff check` as another CI step for lint diagnostics and import order.

Apply import sorting rules sort-imports

ruff check --select I --fix .

# pyproject.toml
[tool.ruff.lint.isort]
known-first-party = ["myapp"]

`ruff format` does not reorder imports. Ruff's isort-compatible behavior lives under the linter's `I` rule family.

Scope rule exceptions by path ignore-test-files

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S101"]
"**/__init__.py" = ["F401"]

Per-file ignores preserve the rule elsewhere. Keep both the glob and code list narrower than a project-wide ignore.

Suppress one named diagnostic suppress-one-line

import plugin_registry  # noqa: F401

# Find suppressions that no longer hide a diagnostic
# ruff check --select RUF100 .

A bare `noqa` suppresses every finding on the line. Naming `F401` leaves unrelated diagnostics active.

Add generated paths to exclusions exclude-generated-code

[tool.ruff]
extend-exclude = [
  "migrations",
  "generated",
  "*_pb2.py",
]

`extend-exclude` adds to Ruff's defaults. Setting `exclude` replaces the existing exclusion list.

Run lint fixes before formatting configure-pre-commit

- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.16.4
  hooks:
    - id: ruff-check
      args: [--fix]
    - id: ruff-format

Put the lint-fix hook first because its changes may need a formatter pass. Pin the hook revision to the project version.

Pin the CI action's Ruff version configure-github-action

- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v3
  with:
    version: "0.16.4"
    args: "check --output-format=github"

Pinning `version` prevents CI from adopting a new Ruff minor before local dependencies and configuration are updated.

Read the installed explanation for a rule inspect-rule

ruff rule F401
ruff rule B008

`ruff rule` prints the explanation, examples, origin, and fix details that belong to the installed Ruff release.

Produce machine-readable findings emit-json-diagnostics

ruff check . --output-format json > ruff-findings.json

JSON output is for reporting and integrations. The command's nonzero status still indicates that lint findings were present.

Alternatives

PackageRegistryPick it when
flake8PyPIKeep it when a required third-party plugin has no corresponding Ruff rule family.
pylintPyPIUse it when its deeper inference and project-specific diagnostics matter more than lint speed.
blackPyPIUse it when formatting is the only requirement and exact Black ownership is part of the policy.
isortPyPIKeep it when an established import-sorting configuration uses behavior Ruff cannot reproduce.

More cli & tooling guides

commander · chalk · typescript · esbuild · yargs · click · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.