[flake8-comprehensions] NFKC-normalize keyword names in C408 fix - #26813
Merged
ntBre merged 2 commits intoJul 24, 2026
Merged
Conversation
Python normalizes identifiers to NFKC, but does not normalize string
literals. The fix for `unnecessary-collection-call` (C408) reparses the
call with libcst, which — unlike Ruff's own parser — does not normalize
identifiers, and then emits the raw source text of each keyword argument
as a dictionary key. This changed the key at runtime: `dict(ℼ=3.14)` has
the key `π`, but was rewritten to `{"ℼ": 3.14}`.
Normalize the keyword name before quoting it, matching what
`fix::codemods` already does for qualified names built from libCST nodes.
Fixes astral-sh#16234
|
ntBre
approved these changes
Jul 24, 2026
ntBre
left a comment
Contributor
There was a problem hiding this comment.
Thanks! One very small nit, which I'll just go ahead and apply, assuming it doesn't break anything!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Python normalizes identifiers to NFKC, but does not normalize string literals. The fix for
unnecessary-collection-call(C408) reparses the call with libcst, which — unlike Ruff's own parser — does not normalize identifiers, and then emits the raw source text of each keyword argument as a dictionary key. This changed the key at runtime:dict(ℼ=3.14)has the keyπ, but was rewritten to{"ℼ": 3.14}.Normalize the keyword name before quoting it, matching what
fix::codemodsalready does for qualified names built from libCST nodes.Fixes #16234
Summary
Python normalizes identifiers to NFKC, but not string literals. The C408 fix
re-parses the call with libcst, and that parser has a particular quirk: it does
not normalize (Ruff's own parser does). So libcst hands over the raw source text
of the kwarg as the key.
dict(ℼ=3.14)has the keyπat RUNTIME, but was rewritten to{"ℼ": 3.14}>this changes the behavior.
My fix normalizes the kwarg name before quoting it. I'm not creating anything
new, because
fix::codemodsalready does the same thing.I decided not to mark it as unsafe, because the C408 fix is already unsafe. And
unlike B009/B010/B043 (string > identifier, where preserving the behavior is
impossible), C408 goes identifier > string. So the correct key can be computed :)
Test Plan
C408.py:ℼ→π,ſ→s,𝕒→a, plus an ASCII control with no changes.allow_dict_calls_with_keyword_argumentssnapshot stayed INTACT.cargo test -p ruff_linter: 2811 passed, 0 failed :)clippy --workspace --all-features -D warnings: 100% clean.generate-all: up-to-date. Andprek run -a: 14/14.Fixes #16234