Skip to content

[flake8-simplify] Preserve f-string source verbatim in SIM101 fix#25061

Merged
MichaReiser merged 5 commits into
astral-sh:mainfrom
adityasingh2400:fix-sim101-fstring-fix
May 15, 2026
Merged

[flake8-simplify] Preserve f-string source verbatim in SIM101 fix#25061
MichaReiser merged 5 commits into
astral-sh:mainfrom
adityasingh2400:fix-sim101-fstring-fix

Conversation

@adityasingh2400

Copy link
Copy Markdown
Contributor

Closes #19601.

The previous fix built a new isinstance(target, (t1, t2)) AST and ran the codegen generator over the entire surrounding BoolOp. Re-rendering through the generator normalizes the source — escape sequences in f-string format specs (\\x7d}) get materialized as literal characters, lambdas inside f-string interpolations get re-spelled, and the result is either a syntax error (the rule's own fix-validator refuses to apply it) or a behavior change.

This switches the fix to splice the original target and type expressions out of the source via the locator, then build the replacement string and replace just the consecutive duplicate-call range, leaving the rest of the BoolOp source untouched. New regression fixtures cover f-strings containing lambdas, lambdas in format specs, and the two escape-sequence cases from the issue body.

@astral-sh-bot astral-sh-bot Bot requested a review from ntBre May 8, 2026 22:53
@MichaReiser

Copy link
Copy Markdown
Member

Thank you.

Fixing the following snippet creates a syntax error on this branch

types = (int,)
isinstance(x, (*types,)) or isinstance(x, ())

@MichaReiser MichaReiser added the fixes Related to suggested fixes for violations label May 11, 2026
…rred element

Empty tuple and starred-only tuple operands could collapse to a single
starred element after splicing, which is a syntax error (e.g.
`isinstance(x, (*types,)) or isinstance(x, ())` was rewritten to
`isinstance(x, (*types))`). Detect this case up front and suppress the
autofix; the diagnostic still fires.
@adityasingh2400

Copy link
Copy Markdown
Contributor Author

Fixed in a199ab5. The merger now flattens the type expressions up front and suppresses the autofix when that would collapse to a single starred element. The diagnostic still fires.

types = (int,)
isinstance(x, (*types,)) or isinstance(x, ())

now reports SIM101 without an offered fix; --fix leaves the source unchanged. Mixed starred-plus-named operands such as isinstance(x, (*types,)) or isinstance(x, int) still merge to isinstance(x, (*types, int)).

@MichaReiser MichaReiser left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This now generates invalid syntax when the expression is parenthesized

((isinstance(x, int)) or isinstance(x, str))

@@ -411,70 +411,52 @@ pub(crate) fn duplicate_isinstance_call(checker: &Checker, expr: &Expr) {
})
.collect();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we still need this collect?

The replacement range only spanned the first and last operand expressions
themselves, so parentheses that wrapped just one operand within the
`BoolOp` were left dangling, producing invalid syntax for inputs like
`((isinstance(x, int)) or isinstance(x, str))`. Extend the range with
`parenthesized_range` to absorb those parens.
@adityasingh2400

Copy link
Copy Markdown
Contributor Author

The replacement range only covered values[first..=last], so a parenthesis wrapping just one operand inside the BoolOp (e.g. ((isinstance(x, int)) or isinstance(x, str))) was left dangling against the merged call that brings its own balance. Extending start/end with parenthesized_range absorbs those parens; the example now fixes to (isinstance(x, (int, str))). As a side effect the existing if(isinstance(a, int)) or (isinstance(a, float)): regression now produces if isinstance(a, (int, float)): instead of if(isinstance(a, (int, float))):, which the snapshot reflects.

Dropped the intermediate types collect — the map chains directly into flat_map now.

@astral-sh-bot

astral-sh-bot Bot commented May 13, 2026

Copy link
Copy Markdown

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@MichaReiser MichaReiser merged commit 63850db into astral-sh:main May 15, 2026
44 checks passed
thejchap pushed a commit to thejchap/ruff that referenced this pull request May 23, 2026
anishgirianish pushed a commit to anishgirianish/ruff that referenced this pull request May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fixes Related to suggested fixes for violations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SIM101 fix introduces errors by normalizing f-strings

3 participants