Ruff v0.13.0 is available now! Install it from PyPI, or with your package manager of choice:
uv tool install ruff@latest
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.13 #
Ruff v0.13 has only a few breaking changes, and most users should expect to upgrade without any updates to their code or configuration. A few of the possible exceptions are described in more detail below.
Several rules can now add from __future__ import annotations
automatically #
Some rules that behave differently when annotations are not evaluated at runtime can now add a
__future__
import as part of their fixes.
Adding from __future__ import annotations
to a Python file enables PEP-563 deferred
annotations. Deferring annotations in this way allows for a few common patterns, such as avoiding
the overhead of an expensive import or enabling recursive type definitions. Several Ruff rules,
namely TC001
, TC002
, TC003
, RUF013
, and
UP037
, can take advantage of this to offer different fixes in the presence of deferred
annotations. For the TC
rules, this means that more imports can be moved into TYPE_CHECKING
blocks, while UP037
can unquote more annotations, and RUF013
can use PEP-604 unions
(e.g. str | int
) on Python versions before 3.10.
This behavior can be enabled via the new lint.future-annotations
setting, which is still off by
default. Note also that other UP
rules like UP006
, UP007
, and
UP045
do not yet use this new functionality. Instead, they still rely on the use of
FA100
to add the __future__
import.
Full module paths are now used to verify first-party modules #
Ruff now checks that the full path to a module exists on disk before categorizing it as a first-party import.
For example, import foo.bar.baz
will only be marked as first-party if foo/bar/baz
is a
directory, or foo/bar
is a directory containing baz.py
or baz.pyi
. This change makes
first-party import detection more accurate, helping to avoid false positives on local directories
with the same name as a third-party dependency, for example. This change most often affects import
sorting rules like I001
, but a few other rules like TC001
, TC002
,
and TC003
rely on this import categorization too.
See the FAQ section on import categorization for more details.
Deprecated rules must now be selected by exact rule code #
Ruff will no longer activate deprecated rules selected by their group name or prefix.
On Ruff v0.12, selecting a group of rules with their prefix, such as the pyupgrade
rules with
UP
, would activate both the stable and deprecated rules. Starting with v0.13, this is no longer
the case. Deprecated rules must be selected with their full rule code. Sticking with the UP
example, a selection like this would be required to select all of the UP
rules, including the
deprecated UP038
1:
ruff check my_code.py --select UP,UP038
This builds on a change from Ruff v0.5, where the special ALL
rule selector was updated to
exclude deprecated rules. This change should help to prevent new users from activating deprecated
rules by mistake and also surface deprecation warnings earlier to make future breaking changes
smoother for everyone.
The deprecated macOS configuration directory fallback has been removed #
Ruff will no longer look for a user-level configuration file at
~/Library/Application Support/ruff/ruff.toml
on macOS.
This feature was deprecated in favor of using the XDG specification (usually resolving to
~/.config/ruff/ruff.toml
), like on Linux. That deprecation also took place in v0.5,
when the XDG directory was made the default, and a warning was added if files were found in
~/Library/Application Support
. The fallback and warning have now been removed.
Rule stabilizations #
The following rules have been stabilized and are no longer in preview:
airflow-dag-no-schedule-argument
(AIR002
)airflow3-removal
(AIR301
)airflow3-moved-to-provider
(AIR302
)airflow3-suggested-update
(AIR311
)airflow3-suggested-to-move-to-provider
(AIR312
)long-sleep-not-forever
(ASYNC116
)f-string-number-format
(FURB116
)os-symlink
(PTH211
)generic-not-last-base-class
(PYI059
)redundant-none-literal
(PYI061
)pytest-raises-ambiguous-pattern
(RUF043
)unused-unpacked-variable
(RUF059
)useless-class-metaclass-type
(UP050
)
Other behavior stabilizations #
This release also stabilizes some additional behavior, previously only available in preview mode:
assert-raises-exception
(B017
) now checks for direct calls tounittest.TestCase.assert_raises
andpytest.raises
instead of only the context manager forms.missing-trailing-comma
(COM812
) andprohibited-trailing-comma
(COM819
) now check for trailing commas in PEP 695 type parameter lists.raw-string-in-exception
(EM101
) now also checks for byte strings in exception messages.invalid-mock-access
(PGH005
) now checks forAsyncMock
methods likenot_awaited
in addition to the synchronous variants.useless-import-alias
(PLC0414
) no longer applies to__init__.py
files, where it conflicted with one of the suggested fixes forunused-import
(F401
).bidirectional-unicode
(PLE2502
) now also checks for U+061C (Arabic Letter Mark).- The fix for
multiple-with-statements
(SIM117
) is now marked as always safe.
Rule removals #
pandas-df-variable-name
(PD901
) has been removed. It was deprecated in v0.12 because it was highly opinionated and less likely to be useful than the otherPD
rules.non-pep604-isinstance
(UP038
) has also been removed. It was deprecated in v0.10 because the PEP 604 union syntax inisinstance
andissubclass
calls is not actually idiomatic and may also hurt performance. See this issue and its references for more details.
See the full changelog on GitHub for other, smaller changes.
Thank you! #
Thank you to everyone who provided feedback regarding the changes included in Ruff's preview mode and to our contributors. It's an honor building Ruff with you!
View the full changelog on GitHub.
Read more about Astral — the company behind Ruff.