Skip to content

Ruff 0.12 #18427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Jun 17, 2025
Merged

Ruff 0.12 #18427

merged 35 commits into from
Jun 17, 2025

Conversation

ntBre
Copy link
Contributor

@ntBre ntBre commented Jun 2, 2025

Summary

Release branch for Ruff 0.12.0

Breaking changes

Behavior changes

Recoded rules

Deprecated rules

Changed rules

Removed rules

Stabilized rules

New or improved fixes

Deferred stabilizations

TODOs

  • Drop empty first commit (random whitespace change to get a baseline ecosystem check executable)
  • Merge with rebase-merge (don't squash merge!!!!)

Tests

Ruff invocations on examples to verify that behavior has been stabilized correctly.
# example.py
# ruff: noqa: RUF001 # should trigger RUF100 unused
with open("file.txt") as f:
    for line in f.readlines(): # FURB129 safe fix
        ...

arr = [1,2,3]
sliceconcat = arr[1:] + [4,5,6] # RUF005 unsafe fix

from typing import Generic, ParamSpec, TypeVar, TypeVarTuple

U = TypeVar("U")
P = ParamSpec("P")
Ts = TypeVarTuple("Ts")


class C[T](Generic[U, P, *Ts]): ...  # RUF053

from datetime import datetime

date = "2025-01-01T00:00:00Z"

datetime.fromisoformat(date.replace("Z", "+00:00"))  # FURB162

if cond: # SIM108 fix should suggest `z = cond or other_cond`
    z = cond
else:
    z = other_cond

match x: # unsupported syntax before python 3.10
    case "a":
        ...

def foo(a,a): ... # semantic syntax error duplicate parameter names

def bar(a: bool | None): ... # FBT001

import subprocess

subprocess.run("true") # should _not_ trigger S603

class GenericClass[_T]:  # UP049
    var: _T

from decimal import Decimal

Decimal("0") # FURB157
Decimal(float("Infinity"))

def decorator():
    pass


@decorator
# fmt: off # RUF028
def example():
    if True:
        # fmt: skip
        expression = [
            # fmt: off
            1,
            2,
        ]
        # yapf: disable
    # fmt: on
    # yapf: enable

def print_python_version():
    import platform # PLC0415

    print(python.python_version())

num = "0xABC"

if num.startswith("0b"):
    i = int(num[2:], 2) # FURB166
elif num.startswith("0o"):
    i = int(num[2:], 8)
elif num.startswith("0x"):
    i = int(num[2:], 16)

print(i)

class Person: # PLW1641
    def __init__(self):
        self.name = "monty"

    def __eq__(self, other):
        return isinstance(other, Person) and other.name == self.name


a = round(1, 0) # RUF057

nums = {123, 456}

if 123 in nums: # FURB132
    nums.remove(123)

if x == float("NaN"):
    pass

def test_foo(a=1): ... # PT028

import pytest


def test_foo_warns():
    with pytest.warns(Warning): # PT031
        setup()  # False negative if setup triggers a warning but foo does not.
        foo()

from pathlib import Path 

with Path("file").open("w") as f:
    for line in lines:
        f.write(line) # FURB122

with Path("file").open("wb") as f:
    for line in lines:
        f.write(line.encode())

import pytest


def test_foo():
    with pytest.warns(RuntimeWarning): # PT030
        ...

    # empty string is also an error
    with pytest.warns(RuntimeWarning, match=""):
        ...

from typing import Optional

foo: Optional[int] = None # UP045 and _not_ UP007

import logging

logging.warning("Foobar", exc_info=ValueError("foo"))  # LOG014

from itertools import starmap

starmap(func, zip(a, b))  # RUF058

from dataclasses import dataclass
from enum import Enum

@dataclass
class E(Enum): ... # RUF049

FRUITS = {"apple": 1, "orange": 10, "berry": 22}

for fruit_name, fruit_count in FRUITS.items():
    print(FRUITS[fruit_name]) # PLR1733

def foo(bar,other_cond): # RET503
    if not bar:
        return 1
    if other_cond:
        return 2
ruff check example.py --no-cache \
    --select FURB129 \
    --select RUF053 --target-version py312 \
    --select FURB162 \
    --select SIM108 \
    --select RUF100 \
    --select FBT001 \
    --select UP049 \
    --select S603 \
    --select FURB157 \
    --select RUF028 \
    --select PLC0415 \
    --select FURB166 \
    --select PLW1641 \
    --select RUF057 \
    --select FURB132 \
    --select PLW0177 \
    --select PT028 \
    --select PT031 \
    --select FURB122 \
    --select PT031 \
    --select UP045 \
    --select UP007 \
    --select LOG014 \
    --select RUF058 \
    --select RUF049 \
    --select PLR1733 \
    --select RET503

Note: Run the above with both --diff and --statistics to see behavior changes for fixes as well as rule stabilizations (and the stabilization of syntax/semantic errors).

ruff check example.py --no-cache \
    --select RUF005 \
    --target-version py39 \
    --unsafe-fixes
    --diff

The below should offer a fix to remove the import:

echo "from __future__ import annotations" | ruff check --no-cache --isolated --diff --stdin-filename ex.pyi --select PYI044 -

@ntBre ntBre added this to the v0.12 milestone Jun 2, 2025
@ntBre ntBre added breaking Breaking API change release Related to the release process labels Jun 2, 2025
@ntBre ntBre force-pushed the brent/release-0.12.0 branch 2 times, most recently from 5f1af44 to 11966be Compare June 6, 2025 14:14
Copy link
Contributor

github-actions bot commented Jun 6, 2025

ruff-ecosystem results

Linter (stable)

ℹ️ ecosystem check detected linter changes. (+10101 -1532 violations, +18 -0 fixes in 27 projects; 28 projects unchanged)

DisnakeDev/disnake (+71 -0 violations, +0 -0 fixes)

+ disnake/abc.py:1722:13: PLC0415 `import` should be at the top-level of a file
+ disnake/abc.py:1932:9: PLC0415 `import` should be at the top-level of a file
+ disnake/app_commands.py:1213:7: PLW1641 Object does not implement `__hash__` method
+ disnake/app_commands.py:162:7: PLW1641 Object does not implement `__hash__` method
+ disnake/app_commands.py:469:7: PLW1641 Object does not implement `__hash__` method
+ disnake/app_commands.py:95:7: PLW1641 Object does not implement `__hash__` method
+ disnake/app_commands.py:993:7: PLW1641 Object does not implement `__hash__` method
+ disnake/appinfo.py:242:9: PLC0415 `import` should be at the top-level of a file
+ disnake/audit_logs.py:180:5: PLC0415 `import` should be at the top-level of a file
+ disnake/channel.py:1535:9: PLC0415 `import` should be at the top-level of a file
... 61 additional changes omitted for project

PlasmaPy/PlasmaPy (+60 -0 violations, +0 -0 fixes)

+ src/plasmapy/__init__.py:83:5: PLC0415 `import` should be at the top-level of a file
+ src/plasmapy/__init__.py:84:5: PLC0415 `import` should be at the top-level of a file
+ src/plasmapy/analysis/nullpoint.py:108:7: PLW1641 Object does not implement `__hash__` method
+ src/plasmapy/diagnostics/langmuir.py:1086:9: PLC0415 `import` should be at the top-level of a file
+ src/plasmapy/diagnostics/langmuir.py:1239:9: PLC0415 `import` should be at the top-level of a file
+ src/plasmapy/diagnostics/langmuir.py:1306:9: PLC0415 `import` should be at the top-level of a file
+ src/plasmapy/diagnostics/langmuir.py:1401:9: PLC0415 `import` should be at the top-level of a file
... 9 additional changes omitted for rule PLC0415
+ src/plasmapy/formulary/relativity.py:191:7: PLW1641 Object does not implement `__hash__` method
+ src/plasmapy/particles/ionization_state.py:169:7: PLW1641 Object does not implement `__hash__` method
+ src/plasmapy/particles/ionization_state.py:32:7: PLW1641 Object does not implement `__hash__` method
... 50 additional changes omitted for project

apache/airflow (+2921 -213 violations, +14 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --no-preview --select ALL

+ airflow-core/hatch_build.py:91:13: PLC0415 `import` should be at the top-level of a file
+ airflow-core/src/airflow/__init__.py:113:5: PLC0415 `import` should be at the top-level of a file
+ airflow-core/src/airflow/__main__.py:52:9: PLC0415 `import` should be at the top-level of a file
+ airflow-core/src/airflow/api_fastapi/app.py:171:5: PLC0415 `import` should be at the top-level of a file
+ airflow-core/src/airflow/api_fastapi/auth/managers/simple/simple_auth_manager.py:281:9: PLC0415 `import` should be at the top-level of a file
+ airflow-core/src/airflow/api_fastapi/auth/tokens.py:227:9: PLC0415 `import` should be at the top-level of a file
... 2562 additional changes omitted for rule PLC0415
+ airflow-core/src/airflow/api_fastapi/common/parameters.py:690:23: FBT001 Boolean-typed positional argument in function definition
+ airflow-core/src/airflow/api_fastapi/core_api/routes/public/job.py:102:5: FBT001 Boolean-typed positional argument in function definition
+ airflow-core/src/airflow/api_fastapi/execution_api/app.py:187:55: LOG014 `exc_info=` outside exception handlers
- airflow-core/src/airflow/cli/commands/dag_command.py:207:14: S603 `subprocess` call: check for execution of untrusted input
- airflow-core/src/airflow/example_dags/tutorial_objectstorage.py:93:9: PD901 Avoid using the generic variable name `df` for DataFrames
+ airflow-core/src/airflow/logging_config.py:38:1: RET503 Missing explicit `return` at the end of function able to return non-`None` value
- airflow-core/src/airflow/logging_config.py:39:5: RET503 Missing explicit `return` at the end of function able to return non-`None` value
... 3135 additional changes omitted for project

apache/superset (+1914 -1105 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --no-preview --select ALL

- RELEASING/changelog.py:106:53: UP007 [*] Use `X | Y` for type annotations
+ RELEASING/changelog.py:106:53: UP045 [*] Use `X | None` for type annotations
+ RELEASING/changelog.py:39:7: PLW1641 Object does not implement `__hash__` method
- RELEASING/changelog.py:72:23: UP007 [*] Use `X | Y` for type annotations
+ RELEASING/changelog.py:72:23: UP045 [*] Use `X | None` for type annotations
- RELEASING/changelog.py:73:15: UP007 [*] Use `X | Y` for type annotations
+ RELEASING/changelog.py:73:15: UP045 [*] Use `X | None` for type annotations
+ RELEASING/changelog.py:73:9: FBT001 Boolean-typed positional argument in function definition
- RELEASING/changelog.py:78:45: UP007 [*] Use `X | Y` for type annotations
+ RELEASING/changelog.py:78:45: UP045 [*] Use `X | None` for type annotations
- RELEASING/verify_release.py:59:42: UP007 [*] Use `X | Y` for type annotations
+ RELEASING/verify_release.py:59:42: UP045 [*] Use `X | None` for type annotations
... 3007 additional changes omitted for project

aws/aws-sam-cli (+174 -0 violations, +0 -0 fixes)

+ samcli/cli/context.py:208:9: PLC0415 `import` should be at the top-level of a file
+ samcli/cli/context.py:209:9: PLC0415 `import` should be at the top-level of a file
+ samcli/cli/main.py:134:5: PLC0415 `import` should be at the top-level of a file
+ samcli/cli/main.py:136:5: PLC0415 `import` should be at the top-level of a file
+ samcli/cli/main.py:143:9: PLC0415 `import` should be at the top-level of a file
+ samcli/cli/options.py:43:9: PLC0415 `import` should be at the top-level of a file
... 155 additional changes omitted for rule PLC0415
+ samcli/lib/build/build_graph.py:515:7: PLW1641 Object does not implement `__hash__` method
+ samcli/lib/build/build_graph.py:579:7: PLW1641 Object does not implement `__hash__` method
+ samcli/lib/observability/cw_logs/cw_log_event.py:10:7: PLW1641 Object does not implement `__hash__` method
+ samcli/lib/providers/provider.py:182:7: PLW1641 Object does not implement `__hash__` method
... 164 additional changes omitted for project

binary-husky/gpt_academic (+12 -11 violations, +0 -0 fixes)

- crazy_functions/doc_fns/read_fns/excel_reader.py:186:22: UP007 Use `X | Y` for type annotations
+ crazy_functions/doc_fns/read_fns/excel_reader.py:186:22: UP045 Use `X | None` for type annotations
- crazy_functions/doc_fns/read_fns/excel_reader.py:40:32: UP007 Use `X | Y` for type annotations
+ crazy_functions/doc_fns/read_fns/excel_reader.py:40:32: UP045 Use `X | None` for type annotations
- crazy_functions/doc_fns/read_fns/excel_reader.py:96:60: UP007 Use `X | Y` for type annotations
+ crazy_functions/doc_fns/read_fns/excel_reader.py:96:60: UP045 Use `X | None` for type annotations
- crazy_functions/doc_fns/read_fns/markitdown/markdown_reader.py:171:26: UP007 Use `X | Y` for type annotations
+ crazy_functions/doc_fns/read_fns/markitdown/markdown_reader.py:171:26: UP045 Use `X | None` for type annotations
- crazy_functions/doc_fns/read_fns/markitdown/markdown_reader.py:46:17: UP007 Use `X | Y` for type annotations
+ crazy_functions/doc_fns/read_fns/markitdown/markdown_reader.py:46:17: UP045 Use `X | None` for type annotations
... 13 additional changes omitted for project

bokeh/bokeh (+369 -148 violations, +4 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --no-preview --select ALL

- examples/basic/annotations/band.py:21:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/annotations/band.py:25:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/annotations/polygon_annotation.py:12:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/areas/stacked_area.py:16:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/axes/datetime_axis.py:6:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/bars/intervals.py:14:1: PD901 Avoid using the generic variable name `df` for DataFrames
... 86 additional changes omitted for rule PD901
+ examples/output/apis/autoload_static_flask.py:10:5: PLC0415 `import` should be at the top-level of a file
+ examples/output/apis/autoload_static_flask.py:11:5: PLC0415 `import` should be at the top-level of a file
+ examples/output/apis/autoload_static_flask.py:7:5: PLC0415 `import` should be at the top-level of a file
+ examples/output/apis/autoload_static_flask.py:9:5: PLC0415 `import` should be at the top-level of a file
... 511 additional changes omitted for project

freedomofpress/securedrop (+13 -0 violations, +0 -0 fixes)

+ securedrop/models.py:312:7: PLW1641 Object does not implement `__hash__` method
+ securedrop/tests/functional/conftest.py:292:5: PLC0415 `import` should be at the top-level of a file
+ securedrop/tests/functional/conftest.py:293:5: PLC0415 `import` should be at the top-level of a file
+ securedrop/tests/functional/conftest.py:294:5: PLC0415 `import` should be at the top-level of a file
+ securedrop/tests/functional/conftest.py:295:5: PLC0415 `import` should be at the top-level of a file
+ securedrop/tests/functional/conftest.py:296:5: PLC0415 `import` should be at the top-level of a file
+ securedrop/tests/functional/conftest.py:59:5: PLC0415 `import` should be at the top-level of a file
... 7 additional changes omitted for rule PLC0415
... 6 additional changes omitted for project

... Truncated remaining completed project reports due to GitHub comment length restrictions

Changes by rule (27 rules affected)

code total + violation - violation + fix - fix
PLC0415 6021 6021 0 0 0
UP045 3082 3082 0 0 0
UP007 857 0 857 0 0
PD901 431 0 431 0 0
RET503 289 134 155 0 0
FBT001 224 224 0 0 0
PT031 159 159 0 0 0
PLW1641 152 152 0 0 0
PLW0177 94 94 0 0 0
PT028 91 91 0 0 0
S603 70 0 70 0 0
RUF100 36 23 13 0 0
PT030 34 34 0 0 0
RUF005 21 21 0 0 0
PLR1733 19 19 0 0 0
LOG014 16 16 0 0 0
SIM108 13 8 5 0 0
FURB122 10 10 0 0 0
FURB129 10 0 0 10 0
PYI044 8 0 0 8 0
FURB157 4 4 0 0 0
RUF058 3 3 0 0 0
FURB132 2 2 0 0 0
D400 2 1 1 0 0
SyntaxError: 1 1 0 0 0
RUF028 1 1 0 0 0
FURB166 1 1 0 0 0

Linter (preview)

ℹ️ ecosystem check detected linter changes. (+0 -431 violations, +0 -0 fixes in 3 projects; 52 projects unchanged)

apache/airflow (+0 -72 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview --select ALL

- airflow-core/src/airflow/example_dags/tutorial_objectstorage.py:93:9: PD901 Avoid using the generic variable name `df` for DataFrames
- airflow-core/src/airflow/serialization/serializers/pandas.py:68:9: PD901 Avoid using the generic variable name `df` for DataFrames
- dev/airflow_perf/sql_queries.py:186:5: PD901 Avoid using the generic variable name `df` for DataFrames
- dev/stats/explore_pr_candidates.ipynb:cell 3:23:5: PD901 Avoid using the generic variable name `df` for DataFrames
- providers/amazon/tests/unit/amazon/aws/transfers/test_sql_to_s3.py:232:9: PD901 Avoid using the generic variable name `df` for DataFrames
- providers/amazon/tests/unit/amazon/aws/transfers/test_sql_to_s3.py:283:9: PD901 Avoid using the generic variable name `df` for DataFrames
- providers/amazon/tests/unit/amazon/aws/transfers/test_sql_to_s3.py:326:9: PD901 Avoid using the generic variable name `df` for DataFrames
- providers/apache/drill/tests/unit/apache/drill/hooks/test_drill.py:116:9: PD901 Avoid using the generic variable name `df` for DataFrames
- providers/apache/drill/tests/unit/apache/drill/hooks/test_drill.py:99:9: PD901 Avoid using the generic variable name `df` for DataFrames
- providers/apache/druid/tests/unit/apache/druid/hooks/test_druid.py:461:9: PD901 Avoid using the generic variable name `df` for DataFrames
... 62 additional changes omitted for project

apache/superset (+0 -268 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview --select ALL

- superset/charts/client_processing.py:110:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:112:13: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:113:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:114:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:124:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:132:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:136:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:141:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:144:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:147:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:206:17: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:213:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:341:13: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:343:13: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:91:5: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/charts/client_processing.py:95:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/commands/database/uploaders/csv_reader.py:135:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/commands/database/uploaders/excel_reader.py:108:13: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/commands/dataset/importers/v1/utils.py:207:5: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/commands/report/alert.py:179:17: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/commands/report/alert.py:204:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/commands/sql_lab/export.py:104:13: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/commands/sql_lab/export.py:128:13: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/common/query_actions.py:104:5: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/common/query_context_processor.py:268:9: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/common/query_context_processor.py:275:13: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/common/query_context_processor.py:279:17: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/common/query_context_processor.py:287:17: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/common/query_context_processor.py:602:13: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/common/query_context_processor.py:658:17: PD901 Avoid using the generic variable name `df` for DataFrames
- superset/common/query_context_processor.py:665:17: PD901 Avoid using the generic variable name `df` for DataFrames
... 237 additional changes omitted for project

bokeh/bokeh (+0 -91 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --ignore RUF9 --no-fix --output-format concise --preview --select ALL

- examples/basic/annotations/band.py:21:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/annotations/band.py:25:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/annotations/polygon_annotation.py:12:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/areas/stacked_area.py:16:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/axes/datetime_axis.py:6:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/basic/bars/intervals.py:14:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/interaction/legends/legend_hide.py:22:5: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/interaction/legends/legend_mute.py:11:5: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/models/daylight.py:24:1: PD901 Avoid using the generic variable name `df` for DataFrames
- examples/models/trail.py:36:5: PD901 Avoid using the generic variable name `df` for DataFrames
... 81 additional changes omitted for project

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
PD901 431 0 431 0 0

@ntBre ntBre force-pushed the brent/release-0.12.0 branch 7 times, most recently from 351e674 to 4cfaa39 Compare June 12, 2025 16:01
@ntBre ntBre force-pushed the brent/release-0.12.0 branch from 6391de8 to 85bdb1e Compare June 16, 2025 16:17
@ntBre ntBre marked this pull request as ready for review June 17, 2025 12:36
@ntBre ntBre requested a review from AlexWaygood as a code owner June 17, 2025 12:36
@ntBre ntBre requested a review from MichaReiser June 17, 2025 12:36
dylwil3 and others added 13 commits June 17, 2025 09:07
…18496)

Note that the preview behavior was not documented (shame on us!) so the
documentation was not modified.

---------

Co-authored-by: Brent Westbrook <[email protected]>
This PR stabilizes the RUF053 rule by moving it from preview to stable
status for the 0.12.0 release.

## Summary
- **Rule**: RUF053 (`class-with-mixed-type-vars`)
- **Purpose**: Detects classes that have both PEP 695 type parameter
lists while also inheriting from `typing.Generic`
- **Change**: Move from `RuleGroup::Preview` to `RuleGroup::Stable` in
`codes.rs` and migrate preview tests to stable tests

## Verification Links
- **Tests**:
[ruff/mod.rs](https://github.com/astral-sh/ruff/blob/main/crates/ruff_linter/src/rules/ruff/mod.rs#L98)
- Shows RUF053 moved from preview_rules to main rules test function
- **Documentation**:
https://docs.astral.sh/ruff/rules/class-with-mixed-type-vars/ - Current
documentation shows preview status that will be automatically updated
This PR stabilizes the FURB162 rule by moving it from preview to stable
status for the 0.12.0 release.

## Summary
- **Rule**: FURB162 (`fromisoformat-replace-z`)
- **Purpose**: Detects unnecessary timezone replacement operations when
calling `datetime.fromisoformat()`
- **Change**: Move from `RuleGroup::Preview` to `RuleGroup::Stable` in
`codes.rs`

## Verification Links
- **Tests**:
[refurb/mod.rs](https://github.com/astral-sh/ruff/blob/main/crates/ruff_linter/src/rules/refurb/mod.rs#L54)
- Confirms FURB162 has only standard tests, no preview-specific test
cases
- **Documentation**:
https://docs.astral.sh/ruff/rules/fromisoformat-replace-z/ - Current
documentation shows preview status that will be automatically updated
…sions in autofix for `if-else-block-instead-of-if-exp` (`SIM108`) (#18506)
…` (`RUF100`) (#18497)

Note that the preview behavior was not documented (shame on us!) so the
documentation was not modified.

---------

Co-authored-by: Brent Westbrook <[email protected]>
…ype-hint-positional-argument` (`FBT001`) (#18520)

Feel free to complain about the rephrasing in the docs!
## Summary
Stabilizes the UP049 rule (private-type-parameter) by moving it from
Preview to Stable.

UP049 detects and fixes the use of private type parameters (those with
leading underscores) in PEP 695 generic classes and functions.

## Test plan
- Verified that UP049 tests pass:
`crates/ruff_linter/src/rules/pyupgrade/mod.rs`
- Ran full test suite with `make test` 
- Confirmed that no test migration was needed as UP049 was already in
the main `rules` test function

## Rule documentation
https://docs.astral.sh/ruff/rules/private-type-parameter/
dylwil3 and others added 22 commits June 17, 2025 09:07
…d preview behavior for `non-pep604-annotation-union` (`UP007`) (#18505)
…14`) (#18517)

## Summary
- Stabilizes LOG014 (exc-info-outside-except-handler) rule by changing
it from Preview to Stable

## Test plan
- ✅ Rule is already tested in main test function, no migration needed
- ✅ `make check` passes
- ✅ `make test` passes

## Rule Documentation
- [Test
file](https://github.com/astral-sh/ruff/blob/main/crates/ruff_linter/src/rules/flake8_logging/mod.rs#L22-L23)
- [Rule
documentation](https://docs.astral.sh/ruff/rules/exc-info-outside-except-handler/)
## Summary
- Stabilizes RUF058 (starmap-zip) rule by changing it from Preview to
Stable
- Migrates test cases from preview_rules to main rules function 
- Updates snapshots accordingly and removes old preview snapshots

## Test plan
- ✅ Migrated tests from preview to main test function
- ✅ `make check` passes
- ✅ `make test` passes  
- ✅ `make citest` passes (no leftover snapshots)

## Rule Documentation
- [Test
file](https://github.com/astral-sh/ruff/blob/main/crates/ruff_linter/src/rules/ruff/mod.rs#L103-L104)
- [Rule documentation](https://docs.astral.sh/ruff/rules/starmap-zip/)
Summary
--

Closes #13707. The rule was deprecated in 0.10 (#16680) and slated for
removal in either this or the next release.

Test Plan
--

N/a
Summary
--

Deprecates PD901 as part of #7710. I don't feel particularly strongly
about this one, though I have certainly used `df` as a dataframe name in
the past, just going through the open issues in the 0.12 milestone.

Test Plan
--

N/a
## Summary
- Stabilizes UP046 (non-pep695-generic-class) rule by changing it from
Preview to Stable

## Test plan
- ✅ Rule is already tested in main test function, no migration needed
- ✅ `make check` passes
- ✅ `make test` passes

## Rule Documentation
- [Test
file](https://github.com/astral-sh/ruff/blob/main/crates/ruff_linter/src/rules/pyupgrade/mod.rs#L109-L110)
- [Rule
documentation](https://docs.astral.sh/ruff/rules/non-pep695-generic-class/)
## Summary
- Stabilizes UP047 (non-pep695-generic-function) rule by changing it
from Preview to Stable

## Test plan
- ✅ Rule is already tested in main test function, no migration needed
- ✅ `make check` passes
- ✅ `make test` passes

## Rule Documentation
- [Test
file](https://github.com/astral-sh/ruff/blob/main/crates/ruff_linter/src/rules/pyupgrade/mod.rs#L111)
- [Rule
documentation](https://docs.astral.sh/ruff/rules/non-pep695-generic-function/)
…xing `implicit-return` (`RET503`) (#18516)

This involved slightly more code changes than usual for a stabilization
- so maybe worth double-checking the logic!

I did verify by hand that the new stable behavior on the test fixture
matches the old preview behavior, even after the internal refactor.
@ntBre ntBre force-pushed the brent/release-0.12.0 branch from 85bdb1e to dad0ecd Compare June 17, 2025 13:26
@ntBre ntBre merged commit a93992f into main Jun 17, 2025
52 checks passed
@ntBre ntBre deleted the brent/release-0.12.0 branch June 17, 2025 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking Breaking API change release Related to the release process
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants