Skip to content

Conversation

@ntBre
Copy link
Contributor

@ntBre ntBre commented Jun 10, 2025

Summary

Stabilizes LOG004 and updates the documentation to say explicitly that the rule still triggers even when passing the exc_info kwarg (#18044).

Test Plan

Existing tests, which were already in the right place

ntBre and others added 14 commits June 8, 2025 20:14
Summary
--

Release branch for Ruff 0.12.0

TODOs
--

- [ ] Drop empty first commit
- [ ] Merge with rebase-merge (**don't squash merge!!!!**)
…18496)

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

---------

Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
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 <brentrwestbrook@gmail.com>
…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/
…`LOG004`)

Summary
--

Stabilizes LOG004 and updates the documentation to say explicitly that the rule
still triggers even when passing the `exc_info`
kwarg (#18044).

Test Plan
--

Existing tests, which were already in the right place
@ntBre ntBre added the rule Implementing or modifying a lint rule label Jun 10, 2025
@github-actions
Copy link
Contributor

ruff-ecosystem results

Linter (stable)

ℹ️ ecosystem check detected linter changes. (+25 -1 violations, +0 -0 fixes in 4 projects; 51 projects unchanged)

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

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

+ airflow-core/src/airflow/api_fastapi/execution_api/app.py:187:9: LOG004 `.exception()` call outside exception handlers
+ airflow-core/src/airflow/api_fastapi/execution_api/routes/task_instances.py:506:17: LOG004 `.exception()` call outside exception handlers
+ airflow-core/src/airflow/dag_processing/bundles/base.py:373:9: LOG004 `.exception()` call outside exception handlers
+ providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/operators/pod.py:1338:13: LOG004 `.exception()` call outside exception handlers
+ providers/edge3/src/airflow/providers/edge3/worker_api/auth.py:80:5: LOG004 `.exception()` call outside exception handlers
+ providers/edge3/src/airflow/providers/edge3/worker_api/routes/_v2_routes.py:59:5: LOG004 `.exception()` call outside exception handlers
+ providers/google/src/airflow/providers/google/cloud/operators/cloud_sql.py:1046:13: LOG004 `.exception()` call outside exception handlers
+ providers/google/src/airflow/providers/google/cloud/operators/dataproc.py:1604:13: LOG004 `.exception()` call outside exception handlers
+ providers/google/src/airflow/providers/google/cloud/operators/dataproc.py:1760:13: LOG004 `.exception()` call outside exception handlers
+ providers/google/src/airflow/providers/google/cloud/operators/dataproc.py:2258:17: LOG004 `.exception()` call outside exception handlers
+ providers/google/src/airflow/providers/google/cloud/operators/kubernetes_engine.py:318:13: LOG004 `.exception()` call outside exception handlers
+ providers/google/src/airflow/providers/google/cloud/operators/kubernetes_engine.py:511:13: LOG004 `.exception()` call outside exception handlers
+ providers/google/src/airflow/providers/google/cloud/triggers/cloud_batch.py:145:9: LOG004 `.exception()` call outside exception handlers
+ task-sdk/tests/task_sdk/definitions/test_secrets_masker.py:136:9: LOG004 `.exception()` call outside exception handlers

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

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

+ superset/utils/decorators.py:231:13: LOG004 `.exception()` call outside exception handlers
+ superset/views/error_handling.py:210:9: LOG004 `.exception()` call outside exception handlers

rotki/rotki (+0 -1 violations, +0 -0 fixes)

- rotkehlchen/api/server.py:436:42: RUF100 [*] Unused `noqa` directive (non-enabled: `LOG004`)

zulip/zulip (+9 -0 violations, +0 -0 fixes)

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

+ zerver/decorator.py:342:5: LOG004 `.exception()` call outside exception handlers
+ zerver/decorator.py:357:9: LOG004 `.exception()` call outside exception handlers
+ zerver/decorator.py:359:9: LOG004 `.exception()` call outside exception handlers
+ zerver/decorator.py:361:9: LOG004 `.exception()` call outside exception handlers
+ zerver/lib/email_mirror_server.py:144:13: LOG004 `.exception()` call outside exception handlers
+ zerver/lib/remote_server.py:291:9: LOG004 `.exception()` call outside exception handlers
+ zerver/worker/base.py:269:17: LOG004 `.exception()` call outside exception handlers
+ zerver/worker/base.py:271:17: LOG004 `.exception()` call outside exception handlers
+ zerver/worker/email_senders_base.py:39:17: LOG004 `.exception()` call outside exception handlers

Changes by rule (2 rules affected)

code total + violation - violation + fix - fix
LOG004 25 25 0 0 0
RUF100 1 0 1 0 0

Linter (preview)

✅ ecosystem check detected no linter changes.

@ntBre
Copy link
Contributor Author

ntBre commented Jun 10, 2025

I think this example might be a false positive:

https://github.com/zulip/zulip/blob/3dc54a10d7cbfb6f6f66a868a31d17ee9e215f53/zerver/worker/email_senders_base.py#L28-L45

It looks like a closure defined in the except handler will preserve its exc_info in the same call stack:

>>> import logging
>>> l = []
>>> def foo(f): f()
...
>>> try:
...     raise ValueError("my error")
... except ValueError:
...     logging.exception("building on_failure")
...     def on_failure():
...         logging.exception("on_failure called")
...     foo(on_failure)
...     l.append(on_failure)
...
ERROR:root:building on_failure
Traceback (most recent call last):
  File "<python-input-19>", line 2, in <module>
    raise ValueError("my error")
ValueError: my error
ERROR:root:on_failure called
Traceback (most recent call last):
  File "<python-input-19>", line 2, in <module>
    raise ValueError("my error")
ValueError: my error
>>> l[-1]()
ERROR:root:on_failure called
NoneType: None

but not if you store it somewhere else and call it later.

@ntBre ntBre requested a review from dylwil3 June 10, 2025 16:52
@ntBre
Copy link
Contributor Author

ntBre commented Jun 10, 2025

What do you think about the false positive? This is the last LOG rule in preview, but my first thought was to leave it in preview even before this, so I'm happy to leave it for now.

@ntBre ntBre force-pushed the brent/release-0.12.0 branch from aaf6c9b to 96913d1 Compare June 10, 2025 20:44
@ntBre ntBre requested a review from AlexWaygood as a code owner June 10, 2025 20:44
@AlexWaygood AlexWaygood removed their request for review June 10, 2025 20:52
@ntBre ntBre force-pushed the brent/release-0.12.0 branch 2 times, most recently from 3ad0f1f to ff6fb14 Compare June 11, 2025 11:09
@dylwil3
Copy link
Collaborator

dylwil3 commented Jun 12, 2025

I vote to leave it in preview and address the bug!

@ntBre
Copy link
Contributor Author

ntBre commented Jun 12, 2025

Sounds good to me, thanks for opening the issue!

@ntBre ntBre closed this Jun 12, 2025
@ntBre ntBre mentioned this pull request Jun 12, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rule Implementing or modifying a lint rule

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants