changelogs/0.8.x.md
Check out the blog post for a migration guide and overview of the changes!
See also, the "Remapped rules" section which may result in disabled rules.
Default to Python 3.9
Ruff now defaults to Python 3.9 instead of 3.8 if no explicit Python version is configured using ruff.target-version or project.requires-python (#13896)
Changed location of pydoclint diagnostics
pydoclint diagnostics now point to the first-line of the problematic docstring. Previously, this was not the case.
If you've opted into these preview rules but have them suppressed using
noqa comments in
some places, this change may mean that you need to move the noqa suppression
comments. Most users should be unaffected by this change.
Use XDG (i.e. ~/.local/bin) instead of the Cargo home directory in the standalone installer
Previously, Ruff's installer used $CARGO_HOME or ~/.cargo/bin for its target install directory. Now, Ruff will be installed into $XDG_BIN_HOME, $XDG_DATA_HOME/../bin, or ~/.local/bin (in that order).
This change is only relevant to users of the standalone Ruff installer (using the shell or PowerShell script). If you installed Ruff using uv or pip, you should be unaffected.
Changes to the line width calculation
Ruff now uses a new version of the unicode-width Rust crate to calculate the line width. In very rare cases, this may lead to lines containing Unicode characters being reformatted, or being considered too long when they were not before (E501).
The following deprecated rules have been removed:
missing-type-self (ANN101)missing-type-cls (ANN102)syntax-error (E999)pytest-missing-fixture-name-underscore (PT004)pytest-incorrect-fixture-name-underscore (PT005)unpacked-list-comprehension (UP027)The following rules have been remapped to new rule codes:
flake8-type-checking: TCH to TCThe following rules have been stabilized and are no longer in preview:
builtin-import-shadowing (A004)mutable-contextvar-default (B039)fast-api-redundant-response-model (FAST001)fast-api-non-annotated-dependency (FAST002)dict-index-missing-items (PLC0206)pep484-style-positional-only-parameter (PYI063)redundant-final-literal (PYI064)bad-version-info-order (PYI066)parenthesize-chained-operators (RUF021)unsorted-dunder-all (RUF022)unsorted-dunder-slots (RUF023)assert-with-print-message (RUF030)unnecessary-default-type-args (UP043)The following behaviors have been stabilized:
ambiguous-variable-name (E741): Violations in stub files are now ignored. Stub authors typically don't control variable names.printf-string-formatting (UP031): Report all printf-like usages even if no autofix is availableThe following fixes have been stabilized:
zip-instead-of-pairwise (RUF007)flake8-datetimez] Exempt min.time() and max.time() (DTZ901) (#14394)flake8-pie] Mark fix as unsafe if the following statement is a string literal (PIE790) (#14393)flake8-pyi] New rule redundant-none-literal (PYI061) (#14316)flake8-pyi] Add autofix for redundant-numeric-union (PYI041) (#14273)ruff] New rule map-int-version-parsing (RUF048) (#14373)ruff] New rule redundant-bool-literal (RUF038) (#14319)ruff] New rule unraw-re-pattern (RUF039) (#14446)pycodestyle] Exempt pytest.importorskip() calls (E402) (#14474)pylint] Autofix suggests using sets when possible (PLR1714) (#14372)invalid-pyproject-toml (RUF200): Updated to reflect the provisionally accepted PEP 639.flake8-pyi] Avoid panic in unfixable case (PYI041) (#14402)flake8-type-checking] Correctly handle quotes in subscript expression when generating an autofix (#14371)pylint] Suggest correct autofix for __contains__ (PLC2801) (#14424)ignores a rule that has been removed (#14435)lint.flake8-import-conventions.aliases only uses valid module names and aliases (#14477)**) in overlong f-string expressions (#14489)airflow] Avoid implicit schedule argument to DAG and @dag (AIR301) (#14581)flake8-builtins] Exempt private built-in modules (A005) (#14505)flake8-pytest-style] Fix pytest.mark.parametrize rules to check calls instead of decorators (#14515)flake8-type-checking] Implement runtime-cast-value (TC006) (#14511)flake8-type-checking] Implement unquoted-type-alias (TC007) and quoted-type-alias (TC008) (#12927)flake8-use-pathlib] Recommend Path.iterdir() over os.listdir() (PTH208) (#14509)pylint] Extend invalid-envvar-default to detect os.environ.get (PLW1508) (#14512)pylint] Implement len-test (PLC1802) (#14309)refurb] Fix bug where methods defined using lambdas were flagged by FURB118 (#14639)ruff] Auto-add r prefix when string has no backslashes for unraw-re-pattern (RUF039) (#14536)ruff] Implement invalid-assert-message-literal-argument (RUF040) (#14488)ruff] Implement unnecessary-nested-literal (RUF041) (#14323)ruff] Implement unnecessary-regular-expression (RUF055) (#14659)pep8-naming] Eliminate false positives for single-letter names (N811, N814) (#14584)pyflakes] Avoid false positives in @no_type_check contexts (F821, F722) (#14615)ruff] Detect redirected-noqa in file-level comments (RUF101) (#14635)ruff] Mark fixes for unsorted-dunder-all and unsorted-dunder-slots as unsafe when there are complex comments in the sequence (RUF022, RUF023) (#14560)None | None for redundant-none-literal (PYI061) and never-union (RUF020) (#14583, #14589)flake8-bugbear] Fix mutable-contextvar-default to resolve annotated function calls properly (B039) (#14532)flake8-pyi, ruff] Fix traversal of nested literals and unions (PYI016, PYI051, PYI055, PYI062, RUF041) (#14641)flake8-pyi] Avoid rewriting invalid type expressions in unnecessary-type-union (PYI055) (#14660)flake8-type-checking] Avoid syntax errors and type checking problem for quoted annotations autofix (TC003, TC006) (#14634)pylint] Do not wrap function calls in parentheses in the fix for unnecessary-dunder-call (PLC2801) (#14601)ruff] Handle attrs's auto_attribs correctly (RUF009) (#14520)airflow] Avoid deprecated values (AIR302) (#14582)airflow] Extend removed names for AIR302 (#14734)ruff] Extend unnecessary-regular-expression to non-literal strings (RUF055) (#14679)ruff] Implement used-dummy-variable (RUF052) (#14611)ruff] Implement unnecessary-cast-to-int (RUF046) (#14697)airflow] Check AIR001 from builtin or providers operators module (#14631)flake8-pytest-style] Remove @ in pytest.mark.parametrize rule messages (#14770)pandas-vet] Skip rules if the panda module hasn't been seen (#14671)pylint] Fix false negatives for ascii and sorted in len-as-condition (PLC1802) (#14692)refurb] Guard hashlib imports and mark hashlib-digest-hex fix as safe (FURB181) (#14694)flake8-import-conventions] Improve syntax check for aliases supplied in configuration for unconventional-import-alias (ICN001) (#14745)@no_type_check contexts (F821, F722) (#14615) (#14726)pep8-naming] Avoid false positive for class Bar(type(foo)) (N804) (#14683)pycodestyle] Handle f-strings properly for invalid-escape-sequence (W605) (#14748)pylint] Ignore @overload in PLR0904 (#14730)refurb] Handle non-finite decimals in verbose-decimal-constructor (FURB157) (#14596)ruff] Avoid emitting assignment-in-assert when all references to the assigned variable are themselves inside asserts (RUF018) (#14661)flake8-use-pathlib rules (#14741)flake8-comprehensions rules (#14729)flake8-type-checking] Expands TC006 docs to better explain itself (#14749)airflow] Add fix to remove deprecated keyword arguments (AIR302) (#14887)airflow]: Extend rule to include deprecated names for Airflow 3.0 (AIR302) (#14765 and #14804)flake8-bugbear] Improve error messages for except* (B025, B029, B030, B904) (#14815)flake8-bugbear] itertools.batched() without explicit strict (B911) (#14408)flake8-use-pathlib] Dotless suffix passed to Path.with_suffix() (PTH210) (#14779)pylint] Include parentheses and multiple comparators in check for boolean-chained-comparison (PLR1716) (#14781)ruff] Do not simplify round() calls (RUF046) (#14832)ruff] Don't emit used-dummy-variable on function parameters (RUF052) (#14818)ruff] Implement if-key-in-dict-del (RUF051) (#14553)ruff] Mark autofix for RUF052 as always unsafe (#14824)ruff] Teach autofix for used-dummy-variable about TypeVars etc. (RUF052) (#14819)flake8-bugbear] Offer unsafe autofix for no-explicit-stacklevel (B028) (#14829)flake8-pyi] Skip all type definitions in string-or-bytes-too-long (PYI053) (#14797)pyupgrade] Do not report when a UTF-8 comment is followed by a non-UTF-8 one (UP009) (#14728)pyupgrade] Mark fixes for convert-typed-dict-functional-to-class and convert-named-tuple-functional-to-class as unsafe if they will remove comments (UP013, UP014) (#14842)except and except* (#14895)flake8-bugbear] Fix B028 to allow stacklevel to be explicitly assigned as a positional argument (#14868)flake8-bugbear] Skip B028 if warnings.warn is called with *args or **kwargs (#14870)flake8-comprehensions] Skip iterables with named expressions in unnecessary-map (C417) (#14827)flake8-pyi] Also remove self and cls's annotation (PYI034) (#14801)flake8-pytest-style] Fix pytest-parametrize-names-wrong-type (PT006) to edit both argnames and argvalues if both of them are single-element tuples/lists (#14699)perflint] Improve autofix for PERF401 (#14369)pylint] Fix PLW1508 false positive for default string created via a mult operation (#14841)airflow] Extend AIR302 with additional functions and classes (#15015)airflow] Implement moved-to-provider-in-3 for modules that has been moved to Airflow providers (AIR303) (#14764)flake8-use-pathlib] Extend check for invalid path suffix to include the case "." (PTH210) (#14902)perflint] Fix panic in PERF401 when list variable is after the for loop (#14971)perflint] Simplify finding the loop target in PERF401 (#15025)pylint] Preserve original value format (PLR6104) (#14978)ruff] Avoid false positives for RUF027 for typing context bindings (#15037)ruff] Check for ambiguous pattern passed to pytest.raises() (RUF043) (#14966)flake8-bandit] Check S105 for annotated assignment (#15059)flake8-pyi] More autofixes for redundant-none-literal (PYI061) (#14872)pydocstyle] Skip leading whitespace for D403 (#14963)ruff] Skip SQLModel base classes for mutable-class-default (RUF012) (#14949)perflint] Parenthesize walrus expressions in autofix for manual-list-comprehension (PERF401) (#15050)airflow] Extend names moved from core to provider (AIR303) (#15145, #15159, #15196, #15216)airflow] Extend rule to check class attributes, methods, arguments (AIR302) (#15054, #15083)fastapi] Update FAST002 to check keyword-only arguments (#15119)flake8-type-checking] Disable TC006 and TC007 in stub files (#15179)pylint] Detect nested methods correctly (PLW1641) (#15032)ruff] Detect more strict-integer expressions (RUF046) (#14833)ruff] Implement falsy-dict-get-fallback (RUF056) (#15160)ruff] Implement unnecessary-round (RUF057) (#14828)TypedDict keys as non-type-expressions (#15073)flake8-comprehensions] Skip C416 if comprehension contains unpacking (#14909)flake8-pie] Allow cast(SomeType, ...) (PIE796) (#15141)flake8-simplify] More precise inference for dictionaries (SIM300) (#15164)flake8-use-pathlib] Catch redundant joins in PTH201 and avoid syntax errors (#15177)pycodestyle] Preserve original value format (E731) (#15097)pydocstyle] Split on first whitespace character (D403) (#15082)pyupgrade] Add all PEP-585 names to UP006 rule (#5454)flake8-type-checking] Improve flexibility of runtime-evaluated-decorators (#15204)pydocstyle] Add setting to ignore missing documentation for *args and **kwargs parameters (D417) (#15210)ruff] Add an allowlist for unsafe-markup-use (RUF035) (#15076)TypeChecker for detecting fastapi routes (#15093)pycodestyle] Avoid false positives and negatives related to type parameter default syntax (E225, E251) (#15214)shebang-not-executable (EXE001) and add git+windows solution to executable bit (#15208)format]: Preserve multiline implicit concatenated strings in docstring positions (#15126)ruff] Add rule to detect empty literal in deque call (RUF025) (#15104)ruff] Avoid reporting when ndigits is possibly negative (RUF057) (#15234)flake8-todos] remove issue code length restriction (TD003) (#15175)pyflakes] Ignore errors in @no_type_check string annotations (F722, F821) (#15215)--verbose (#15237)