Skip to content

Drop C409 tuple comprehension preview behaviour - #25707

Merged
ntBre merged 6 commits into
astral-sh:mainfrom
Avasam:Only-apply-C409-tuple-comprehension-preview-behaviour-on-Pthon-3.14+
Jul 8, 2026
Merged

Drop C409 tuple comprehension preview behaviour#25707
ntBre merged 6 commits into
astral-sh:mainfrom
Avasam:Only-apply-C409-tuple-comprehension-preview-behaviour-on-Pthon-3.14+

Conversation

@Avasam

@Avasam Avasam commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #12912 by only applying the tuple generator behavior of the rule on Python 3.14+, where tuple generator expression got optimized in (ref: python/cpython#131737). Rendering the concerns on that issue no longer relevant on those Python versions.

This was especially problematic for C409 as only some behaviour is in preview, not the rule itself, so you couldn't use tool.ruff.lint.explicit-preview-rules = true

Test Plan

TODO (haven't installed cargo)
New snapshot should pass on CI


Note: Code changed by Claude Sonnet 4.6. Reviewed by human, although I don't know much about Rust (but this seems a simple enough change)

@astral-sh-bot
astral-sh-bot Bot requested a review from ntBre June 6, 2026 16:43
@Avasam
Avasam force-pushed the Only-apply-C409-tuple-comprehension-preview-behaviour-on-Pthon-3.14+ branch from c85d436 to 712ed7b Compare June 6, 2026 16:49
@astral-sh-bot

astral-sh-bot Bot commented Jun 6, 2026

Copy link
Copy Markdown

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

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

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

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

- airflow-core/tests/unit/always/test_example_dags.py:131:25: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- dev/breeze/src/airflow_breeze/utils/packages.py:437:12: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- devel-common/src/tests_common/_internals/capture_warnings.py:191:55: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- providers/google/src/airflow/providers/google/cloud/transfers/sql_to_gcs.py:262:41: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- providers/oracle/src/airflow/providers/oracle/hooks/handlers.py:31:16: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)

latchbio/latch (+0 -1 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- src/latch/functions/operators.py:106:27: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)

reflex-dev/reflex (+0 -1 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- docs/app/agent_files/_plugin.py:255:12: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)

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

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- astropy/modeling/_fitting_parallel.py:221:28: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- astropy/modeling/_fitting_parallel.py:35:13: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- astropy/modeling/_fitting_parallel.py:44:12: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- astropy/modeling/_fitting_parallel.py:514:20: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- astropy/modeling/_fitting_parallel.py:515:22: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- astropy/modeling/_fitting_parallel.py:518:21: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- astropy/modeling/_fitting_parallel.py:519:23: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- astropy/modeling/_fitting_parallel.py:640:17: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)
- astropy/nddata/covariance.py:114:12: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)

home-assistant/core (+0 -1 violations, +0 -0 fixes)

ruff check --no-cache --exit-zero --no-fix --output-format concise --preview

- tests/components/vera/common.py:99:29: unnecessary-literal-within-tuple-call Unnecessary list comprehension passed to `tuple()` (rewrite as a generator)

Changes by rule (1 rules affected)

code total + violation - violation + fix - fix
unnecessary-literal-within-tuple-call 17 0 17 0 0

@ntBre

ntBre commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Thanks! It seems like there's not really consensus on what to do about this on the issue. I would personally probably lean toward dropping the preview behavior entirely with the possibility of moving it to a separate rule. It feels a bit strange to me to gate this kind of thing on the Python version, but I'm open to other thoughts.

@ntBre ntBre added rule Implementing or modifying a lint rule needs-decision Awaiting a decision from a maintainer preview Related to preview mode features labels Jun 8, 2026
@Avasam

Avasam commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

I'm also all for dropping it entirely, my change here was simply less "aggressive" than that, in case some Python 3.14+ users liked the preview behaviour.
And yeah, a separate "comprehension/upgrade" style rule that is aware of the Python 3.14+ improvements would be fitting.

@Avasam

Avasam commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Would a separate rule need to be implemented to drop this behaviour from C409?
Or is it acceptable to simply document "Feature Request: Prefer generator for tuple" after dropping the behaviour from C409 ?

I could update this PR either way, create a separate issue if needed, and resolve the concerns of #12912

@ntBre

ntBre commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Let's just drop the preview behavior. The feature has been in preview for almost 2 years now, blocked by #12912, so I think we can just drop it. A follow-up issue does make sense to summarize some of the history and make sure we don't reintroduce the behavior accidentally. I'm happy to write that if you want, or you're certainly welcome to :)

Thank you!

@ntBre ntBre removed the needs-decision Awaiting a decision from a maintainer label Jul 7, 2026
@Avasam

Avasam commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. Before finishing the writeup, I decided to throw an actual test comparing 3.14 and .... I can't even see a noticeable difference there. So I think I won't even make a request for this on 3.14+.

It would also mean that my feature request #11839 is still valid in Python 3.14+

#12912 (comment)

I decided to get some actual numbers on 3.14 for #25707, and unless there's something completely wrong with my test setup, I don't even see any speedup for "literal tuple generator expressions" from python/cpython#131737

$ for py in 3.11 3.12 3.14; do
uv run --python="$py" python -c "
import timeit, sys
print('Python', sys.version)
print('Generator expression:', timeit.timeit('tuple(i for i in range(10000))', number=10000))
print('List comprehension :', timeit.timeit('tuple([i for i in range(10000)])', number=10000))
"
echo
done

Python 3.11.15 (main, Jun  2 2026, 22:26:03) [Clang 22.1.3 ]
Generator expression: 2.359152023000206
List comprehension  : 1.5523815449996619

Python 3.12.13 (main, Jun  2 2026, 22:27:15) [Clang 22.1.3 ]
Generator expression: 2.3193205210009182
List comprehension  : 1.628756488998988

Python 3.14.5 (main, Jun  2 2026, 22:25:17) [Clang 22.1.3 ]
Generator expression: 2.3929332610005076
List comprehension  : 1.9009370889998536

@Avasam Avasam changed the title Only apply C409 tuple comprehension preview behaviour on Python 3.14+ Drop C409 tuple comprehension preview behaviour Jul 7, 2026

@ntBre ntBre left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I just had a small suggestion for one additional deletion.

@ntBre
ntBre merged commit 6c3dab4 into astral-sh:main Jul 8, 2026
47 checks passed
@Avasam
Avasam deleted the Only-apply-C409-tuple-comprehension-preview-behaviour-on-Pthon-3.14+ branch July 8, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Related to preview mode features rule Implementing or modifying a lint rule

Projects

None yet

Development

Successfully merging this pull request may close these issues.

C409 now makes code slower

2 participants