Release Notes
Check out the blog post for a migration guide and overview of the changes!
Breaking changes
Ruff now formats your code according to the 2025 style guide. As a result, your code might now get formatted differently. See the formatter section for a detailed list of changes.
This release doesn’t remove or remap any existing stable rules.
Stabilization
The following rules have been stabilized and are no longer in preview:
stdlib-module-shadowing
(A005
).
This rule has also been renamed: previously, it was calledbuiltin-module-shadowing
.builtin-lambda-argument-shadowing
(A006
)slice-to-remove-prefix-or-suffix
(FURB188
)boolean-chained-comparison
(PLR1716
)decimal-from-float-literal
(RUF032
)post-init-default
(RUF033
)useless-if-else
(RUF034
)
The following behaviors have been stabilized:
pytest-parametrize-names-wrong-type
(PT006
): Detectpytest.parametrize
calls outside decorators and calls with keyword arguments.module-import-not-at-top-of-file
(E402
): Ignorepytest.importorskip
calls between import statements.mutable-dataclass-default
(RUF008
) andfunction-call-in-dataclass-default-argument
(RUF009
): Add support forattrs
.bad-version-info-comparison
(PYI006
): Extend the rule to check non-stub files.
The following fixes or improvements to fixes have been stabilized:
redundant-numeric-union
(PYI041
)duplicate-union-members
(PYI016
)
Formatter
This release introduces the new 2025 stable style (#13371), stabilizing the following changes:
- Format expressions in f-string elements (#7594)
- Alternate quotes for strings inside f-strings (#13860)
- Preserve the casing of hex codes in f-string debug expressions (#14766)
- Choose the quote style for each string literal in an implicitly concatenated f-string rather than for the entire string (#13539)
- Automatically join an implicitly concatenated string into a single string literal if it fits on a single line (#9457)
- Remove the
ISC001
incompatibility warning (#15123) - Prefer parenthesizing the
assert
message over breaking the assertion expression (#9457) - Automatically parenthesize over-long
if
guards inmatch
case
clauses (#13513) - More consistent formatting for
match
case
patterns (#6933) - Avoid unnecessary parentheses around return type annotations (#13381)
- Keep the opening parentheses on the same line as the
if
keyword for comprehensions where the condition has a leading comment (#12282) - More consistent formatting for
with
statements with a single context manager for Python 3.8 or older (#10276) - Correctly calculate the line-width for code blocks in docstrings when using
max-doc-code-line-length = "dynamic"
(#13523)
Preview features
- [
flake8-bugbear
] Implementclass-as-data-structure
(B903
) (#9601) - [
flake8-type-checking
] Applyquoted-type-alias
more eagerly inTYPE_CHECKING
blocks and ignore it in stubs (TC008
) (#15180) - [
pylint
] Ignoreeq-without-hash
in stub files (PLW1641
) (#15310) - [
pyupgrade
] SplitUP007
into two individual rules:UP007
forUnion
andUP045
forOptional
(UP007
,UP045
) (#15313) - [
ruff
] New rule that detects classes that are both an enum and adataclass
(RUF049
) (#15299) - [
ruff
] RecodeRUF025
toRUF037
(RUF037
) (#15258)
Rule changes
- [
flake8-builtins
] Ignorestdlib-module-shadowing
in stub files(A005
) (#15350) - [
flake8-return
] Add support for functions returningtyping.Never
(RET503
) (#15298)
Server
- Improve the observability by removing the need for the "trace" value to turn on or off logging. The server logging is solely controlled using the
logLevel
server setting
which defaults toinfo
. This addresses the issue where users were notified about an error and told to consult the log, but it didn’t contain any messages. (#15232) - Ignore diagnostics from other sources for code action requests (#15373)
CLI
- Improve the error message for
--config key=value
when thekey
is for a table and it’s a simplevalue
Bug fixes
- [
eradicate
] Ignore metadata blocks directly followed by normal blocks (ERA001
) (#15330) - [
flake8-django
] Recognize other magic methods (DJ012
) (#15365) - [
pycodestyle
] Avoid false positives related to type aliases (E252
) (#15356) - [
pydocstyle
] Avoid treating newline-separated sections as sub-sections (D405
) (#15311) - [
pyflakes
] Remove call when removing final argument fromformat
(F523
) (#15309) - [
refurb
] Mark fix as unsafe when the right-hand side is a string (FURB171
) (#15273) - [
ruff
] Treat)
as a regex metacharacter (RUF043
,RUF055
) (#15318) - [
ruff
] Parenthesize theint
-call argument when removing theint
call would change semantics (RUF046
) (#15277)
Contributors
- @AlexWaygood
- @Avasam
- @Daverball
- @Glyphack
- @InSyncWithFoo
- @MichaReiser
- @augustelalande
- @carljm
- @charliermarsh
- @dcreager
- @dhruvmanila
- @diceroll123
- @dylwil3
- @eclbg
- @rtpg
- @sharkdp
- @viccie30
Install ruff 0.9.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/ruff/releases/download/0.9.0/ruff-installer.sh | sh
Install prebuilt binaries via powershell script
powershell -ExecutionPolicy ByPass -c "irm https://github.com/astral-sh/ruff/releases/download/0.9.0/ruff-installer.ps1 | iex"