[ruff] Suppress diagnostic for invalid f-strings before Python 3.12 (RUF027)#23480
[ruff] Suppress diagnostic for invalid f-strings before Python 3.12 (RUF027)#23480ntBre merged 8 commits intoastral-sh:mainfrom
ruff] Suppress diagnostic for invalid f-strings before Python 3.12 (RUF027)#23480Conversation
…hon < 3.12 Comments inside f-string interpolations are only valid in Python 3.12+. The RUF027 fix was not checking for this, causing it to produce invalid f-strings when the interpolation contained a `#` character and the target version was below 3.12. This extends the existing backslash check to also cover comments. Fixes astral-sh#23460
| if target_version < PythonVersion::PY312 && interpolation_text.contains('\\') { | ||
| if target_version < PythonVersion::PY312 | ||
| && (interpolation_text.contains('\\') || interpolation_text.contains('#')) | ||
| { |
There was a problem hiding this comment.
Number signs are only problematic when they would start comments. f"{'#'}" is fine in Python 3.11.
There was a problem hiding this comment.
Good catch! Updated the check to use a has_comment_hash() helper that tracks string nesting — # inside a nested string literal (e.g., f"{'#'}") is now correctly recognized as not a comment.
|
| code | total | + violation | - violation | + fix | - fix |
|---|---|---|---|---|---|
| D420 | 508 | 0 | 508 | 0 | 0 |
| DOC501 | 4 | 2 | 2 | 0 | 0 |
… a string
A '#' character is only a comment when it appears outside of any nested
string literal in the interpolation. For example, f"{'#'}" is valid
Python 3.11 — the '#' is inside a string, not a comment.
Add has_comment_hash() helper that scans interpolation text tracking
string nesting depth to distinguish comment '#' from '#' in strings.
Add test cases for '#' inside nested string literals.
stakeswky
left a comment
There was a problem hiding this comment.
Good catch, thanks! You're right — f"{'#'}" is perfectly valid in Python 3.11 because the # is inside a nested string literal, not a comment.
I've added a has_comment_hash() helper that scans the interpolation text while tracking string nesting depth, so it only returns true when # appears outside of any nested string. The simple interpolation_text.contains('#') check has been replaced with this.
Also added test cases for {'#'} and {"#"} in the fixture to cover this.
ntBre
left a comment
There was a problem hiding this comment.
Looks like there are some compilation errors, and I had one question/concern about the implementation itself while I was here.
crates/ruff_linter/src/rules/ruff/rules/missing_fstring_syntax.rs
Outdated
Show resolved
Hide resolved
- has in the format spec, not a comment; only scan the expression part (before the format spec) for comment hashes - Merge upstream/main to resolve Cargo.lock dependency conflicts - Add test cases for hash-in-format-spec (e.g. , )
…ash/comment check
Instead of manually scanning interpolation text for backslashes and comment
hashes (which failed for nested cases like '{1:{x #}}'), delegate to the
parser's own PEP 701 detection via unsupported_syntax_errors().
- Removes has_comment_hash() and the per-element text scanning
- Handles all nesting levels correctly (nested interpolations in format specs)
- Adds test case for '{1:{x #}}' (comment in nested format-spec interpolation)
Address review feedback: match all Pep701FString variants (Backslash, Comment, NestedQuote) using a wildcard instead of importing the private FStringKind enum. This fixes the compilation error from importing ruff_python_parser::error::FStringKind (private module) and also covers the NestedQuote variant which was previously missed.
|
Thanks for the review @ntBre! I've pushed a fix:
Compilation passes cleanly now. |
ruff] Suppress diagnostic for invalid f-strings before Python 3.12 (RUF027)
Summary
Fixes #23460.
Comments inside f-string interpolations (
#) are only valid in Python 3.12+ (PEP 701). RUF027 was not checking for this, so it could produce invalid f-strings when the interpolation text contained a#andtarget-versionwas below 3.12.Fix
Extended the existing
target_version < PY312backslash check to also cover comments:Test Plan
Added a test fixture with a comment inside an f-string interpolation (
{x # }). The existingassert_diagnostics_diff!test for PY311 vs PY312 will capture the new suppression.Reproducer (from #23460)
On
--target-version py311, this should not trigger RUF027 since the resulting f-string would contain a comment in the interpolation, which is a syntax error before Python 3.12.