ruff is a tool to check and lint Python code. It’s written in Rust and it
really is blazing fast. The first time I ran it on a real codebase I
immediately got an error and, for a split-second, though it was an execution
error. It had actually run successully in a few milliseconds and found an issue
in my code (a silly one, but a valid one).
ruff implements all the rules from
essentially implies it serves as a full replacement for
it implements a lot of rules for
flake8 plugins (these need to be enabled
I’ve transitioned a couple of projects from
flake8 to ruff and I’m very happy
with the results. On top of re-implementing the rules in a very fast way,
ruff also implements “severities”: diagnostic may be Errors, Warnings, Info
or Hint. This helps a lot; when drafting code (e.g.: in a very rough state),
errors (e.g.: missing import, reading from undefined variable, etc) are not the
same as hints (e.g.: missing or extra whitespace, too many empty newlines, etc).
I actually suggested implementing severities for flake8, but this was deemed completely unacceptable; the authors believe that every single user out there should re-implement this mapping themselves, which is an absurd idea that doesn’t scale.
ruff can auto-fix a lot of issues that existing tools could only
detect (for example: rewriting loops using comprehensions).
There’s nothing truly broken with
isort to be honest. It’s a great tool. And
ruff implements all its functionality into the same codebase. It kinda makes
sense; both tools need to parse and entire codebase and analyse it. Adding a
new check to a single tool is simpler implementing two tools. Plus, combining
the auto-fixing of
flake8 rules with auto-fixing of imports into one action
makes code maintenance a lot simpler.
You can see where this is going, right?
ruff also implement fixes done by
For those not familiar,
pyupgrade allows specifying which version of python a
project is targeting, and will automatically update syntax for newer language
and drop obsolete syntax.
This usually removes a lot of redundant code, and updates code to newer (easier to read) syntax.
Aside from fixing these automatically,
ruff will show these potential fixes
as warnings when checking code, or when running via a LSP…
A dedicated language server:
ruff-lsp is a language server built on top of
ruff. It’s very simple and
straightforward to configure in neovim or any of many other code
editors. It provides diagnostics for all of
ruff’s checks, as well as actions
to apply fixes via an IDE’s interface.
My experience so far with
ruff-lsp has been very pleasant. A lot of useful
feedback when editing any Python file. It’s fast, and has very sensible
defaults, so even for projects that don’t have a ruff configuration the
diagnostics are quite valuable (e.g.: unused variable, unused import, missing
definition, all valid checks).
You can read more about
ruff in today’s post by the author. If you’re
interesting in switching a project from
usually pretty straighforward. Here’s an example of how I switched
todoman to use
For project with many developers (e.g.: those where you work in a team), be sure to align with other devs. They will need to ensure that their workflow is updated.