Ruff v0.5.0 is available now! Install it from PyPI, or your package manager of choice:

pip install --upgrade ruff

As a reminder: Ruff is an extremely fast Python linter and formatter, written in Rust. Ruff can be used to replace Black, Flake8 (plus dozens of plugins), isort, pydocstyle, pyupgrade, and more, all while executing tens or hundreds of times faster than any individual tool.


Migrating to v0.5

In most cases, you should be able to upgrade seamlessly to Ruff v0.5 without having to change a thing. Nonetheless, this release includes a few deprecations and breaking changes that may require action when upgrading.

The most notable breaking changes in this release are:

Output format now defaults to full

The exact format Ruff uses to report lint violations is configurable using the --output-format option. Ruff v0.2 introduced a new option --output-format=full: unlike other formats, this displays the code snippet that triggered the lint violation as well as the violation's error code and error message. This can provide important context when you're trying to address a violation reported by Ruff.

We want our diagnostics to be as informative and actionable as possible, so this release makes --output-format=full the default behavior for Ruff. In the future, this change will also enable us to show suggested fixes as part of reporting violations, further improving the experience for our users.

The new default violation format looks like this:

ruff check
bundled/tool/ruff_server.py:2:8: F401 [*] `pathlib` imported but unused
  |
1 | import os
2 | import pathlib
  |        ^^^^^^^ F401
3 | import shutil
4 | import site
  |
  = help: Remove unused import: `pathlib`

Found 1 error.
[*] 1 fixable with the `--fix` option.

Use --output-format=concise or the RUFF_OUTPUT_FORMAT environment variable to go back to a more concise output without code snippets:

ruff check --output-format=concise
bundled/tool/ruff_server.py:2:8: F401 [*] `pathlib` imported but unused
Found 1 error.
[*] 1 fixable with the `--fix` option.

Selecting ALL now excludes deprecated rules

The ALL selector is an easy way to enable all of Ruff's rules from the command line or via a configuration file. In previous releases of Ruff, we took this quite literally — using --select=ALL on the command line selected all of Ruff's rules, even those which were deprecated! This could, in turn, lead to Ruff emitting warnings about deprecated rules having been selected.

Selecting ALL now selects all of Ruff's rules except any rules that have been deprecated. We expect this is what most of our users using --select=ALL wanted all along. Deprecated rules can still be enabled, but you'll now have to explicitly specify them on the command line or in a configuration file:

ruff check my_code.py --select=ALL,DEPRECATED_RULE001

XDG specification now used on macOS

Previously, Ruff discovered user-level configuration in ~/Library/Application Support/ruff/ruff.toml on macOS and followed the XDG specification on other Unix systems (defaulting to ~/.config/ruff/ruff.toml). Ruff now follows the XDG specification on all Unix platforms, including macOS.

When upgrading, Ruff will tell you if you're using a user-level configuration file stored in the Application Support/ruff directory and will give tips on where to move your configuration file.

Rule remappings

Many of Ruff's rules are reimplementations of lints from other, older tools. Occasionally this means we need to merge overlapping rules, remove duplicate rules, or rename rules for consistentency with other linters.

This release merges the [flake8-trio] and flake8-async categories into a single flake8-async category, following the merger of the flake8 plugins from which many of these rules were originally derived. All the rules in these two categories have been remapped to new codes:

flake8-async

  • blocking-http-call-in-async-function: ASYNC100 has been remapped to ASYNC210
  • open-sleep-or-subprocess-in-async-function: ASYNC101 has been split into ASYNC220, ASYNC221, ASYNC230, and ASYNC251
  • blocking-os-call-in-async-function: ASYNC102 has been merged into ASYNC220 and ASYNC221

flake8-trio

Attempting to select rules using the deprecated TRIO codes will cause Ruff to emit a warning; however, Ruff will automatically map the deprecated code to the updated code. The old ASYNC100, ASYNC101, ASYNC102 or ASYNC1 codes will need to be manually updated to their new ASYNC2XX codes.

As well as the ASYNC and TRIO remappings, repeated-isinstance-calls has also been remapped from PLR1701 to SIM101.

Changes to E999 and reporting of syntax errors

Prior to Ruff v0.4.0, Ruff would immediately stop parsing a Python file if it encountered a single syntax error. This meant that Ruff's linter would only report a single violation regarding invalid syntax, even if there was more than one syntax error in the file. With the release of the new hand-written parser in Ruff v0.4.0, Ruff can recover from syntax errors and continue parsing the file. This means Ruff can now report all syntax errors in a file, not just the first one.

The E999 rule was used to report syntax errors, allowing users to silence these reports via Ruff's disablement mechanisms. This release deprecates the E999 rule, which will be removed in a future release. Ruff will now always report all syntax errors it encounters, meaning users can no longer ignore them. The motivation for this change is to ensure users are always aware of syntax errors, as these prevent proper linting. By making syntax error reporting mandatory, we eliminate the risk of users missing these critical issues.

To prepare for this change, we recommend that you remove any disablement of the E999 rule as it will no longer have any effect. You can use our unused-noqa rule and autofix to automatically remove any unused noqa: E999 comments from your code.

New server setting: showSyntaxErrors

Now that Ruff always reports syntax errors, we understand that some users may want to hide these diagnostics in their editor. This is especially relevant when using multiple Python language servers, Ruff being one of them: multiple servers complaining about the same syntax error can create a chaotic user experience.

To accomodate this use case and to give users more control over their editor experience, this release introduces a new showSyntaxErrors server setting. This setting is true by default and controls whether syntax error diagnostics are shown in the editor.

In Ruff's VS Code extension, you can configure this using the ruff.showSyntaxErrors setting:

{
  "ruff.showSyntaxErrors": false
}

In other editors using the new ruff server or ruff-lsp, you can configure this using the showSyntaxErrors server setting. For example, in Neovim you can use the following config:

require('lspconfig').ruff.setup({
  init_options = {
    settings = {
      showSyntaxErrors = false
    },
  },
})
-- Same configuration for `ruff_lsp`

--statistics now shows rule names

ruff check --statistics can be used to get a report summarising all lint violations in your project, grouped by lint rule. The format for this report has now been altered to show the rule's name alongside the rule's code. The new format looks like this:

ruff check . --statistics
236 W191    [ ] tab-indentation
 85 PLR2004 [ ] magic-value-comparison
 84 UP031   [*] printf-string-formatting
 81 PLR0913 [ ] too-many-arguments
 73 RUF012  [ ] mutable-class-default
 65 Q000    [*] bad-quotes-inline-string

Previously, Ruff showed the error message of the first violation instead of the rule's name. However, this could sometimes lead to strange results, as the message can vary between violations of the same rule. For example:

ruff check . --statistics
236 W191    [ ] Indentation contains tabs
 85 PLR2004 [ ] Magic value used in comparison, consider replacing `-128` with a constant variable
 84 UP031   [*] Use format specifiers instead of percent format
 81 PLR0913 [ ] Too many arguments in function definition (10 > 5)
 73 RUF012  [ ] Mutable class attributes should be annotated with `typing.ClassVar`
 65 Q000    [*] Double quotes found but single quotes preferred

Stabilized rules

The following rules have been stabilized and are no longer in preview:

There are many more new rules still in preview. We'd highly recommend checking them out! You can turn on preview and opt-in to rules one-at-a-time.

Stabilized behaviors

Some of our stable lint rules have had their scope significantly expanded or reduced in this release. When we find that we need to make changes like this, we'll often made them in preview mode only (even for stable rules) for several minor releases, before "promoting" the behavior change to stable mode so that all users can benefit from it.

The following behavior changes have been promoted to stable for Ruff v0.5:

Removed deprecated features

This release removes support for the following deprecated features:

CLI

  • ruff <path>: Use ruff check <path>
  • ruff --clean: Use ruff clean
  • ruff --generate-shell-completion: Use ruff generate-shell-completion

Settings

  • output-format=text and show-source:
    • With show-source=true: Use output-format=full
    • With show-source=false: Use output-format=concise
    • Without show-source: We recommend using output-format=full, but concise is also available.
  • tab-size=<size>: Use indent-width=<size>

When upgrading, Ruff will tell you if you use any of these commands or settings and advise you on what command or setting to use instead.


View the full changelog on GitHub.

Read more about Astral — the company behind Ruff.

Thanks to Micha Reiser and Dhruv Manilawala, who both contributed to this blog post.