Update F541 to use new f-string tokens#7327
Conversation
eeadcac to
f1e192f
Compare
2cf76c2 to
0cf830d
Compare
f1e192f to
fbcedf2
Compare
0cf830d to
deeca01
Compare
fbcedf2 to
9c4d048
Compare
deeca01 to
a8b5756
Compare
9c4d048 to
0a404ec
Compare
a8b5756 to
4c2017e
Compare
crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs
Outdated
Show resolved
Hide resolved
crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs
Outdated
Show resolved
Hide resolved
| let first_char = locator.slice(TextRange::at(range.start(), TextSize::from(1))); | ||
| .filter_map(move |(tok, range)| match tok { | ||
| Tok::FStringStart => { | ||
| current_f_string_start = range.start(); |
There was a problem hiding this comment.
How does this work with multiple nested fstrings?
f"{f"{a + f"{b}"}"}"I would expect that f"{b}" overrides the start position of f"{a + f"{b}"}"
There was a problem hiding this comment.
To give some context, the autofix for the rule F541 is to remove the f prefix from the f-string without any placeholders. The placeholder checks are done at an expression level by checking if there's any FormattedValue. The function you're referring to is to get the f prefix range and the f-string range. At this point there can't be any nested f-strings.
Also, the reason the function returns an iterator is because of implicitly concatenated strings.
There was a problem hiding this comment.
I think the function name is a bit confusing which I'll rename. I've also added docs to the function.
There was a problem hiding this comment.
Hmm, but the documentation mentions that this function returns all nested f-string ranges, meaning there need to be placeholders? It's also unclear to me where the filtering out of f-strings without placeholders happens.
So I think we need to update the documentation to match its actual behavior (or it's too early in the morning and I shouldn't be reviewing PR's 😅 )
There was a problem hiding this comment.
Hmm, but the documentation mentions that this function returns all nested f-string ranges, meaning there need to be placeholders?
I've updated the documentation but I'm curious as to where was "nested f-string ranges" mentioned? 😅
| if !values | ||
| .iter() | ||
| .any(|value| matches!(value, Expr::FormattedValue(_))) | ||
| { | ||
| for (prefix_range, tok_range) in |
There was a problem hiding this comment.
It's also unclear to me where the filtering out of f-strings without placeholders happens.
There was a problem hiding this comment.
Thanks. The issue I see is that find_useless_f_strings returns all fstrings but with potentially incorrect ranges. So naming that function find_useless_f_strings is misleading in my view because not all fstrings returned by that function are useless.
There was a problem hiding this comment.
Yes, I totally agree. I've renamed it to fstring_prefix_and_tok_range but the main reason it returns an iterator is because the f-string can contain multiple implicitly concatenated (f-)strings.
because not all fstrings returned by that function are useless.
Can you expand on this? For example, in the below code snippet it would return (prefix range, token range) for the "first" and the "last" string and not for the "normal" string. Both f-strings are useless in the sense that there are no placeholders used and so the f prefix is useless. I don't think it ever returns incorrect ranges.
f"first" "normal" rf"second"
# ^ ^ (prefix range)
# ^^^^^^^^ ^^^^^^^^^^ (token range)
# (0..1, 0..8) - `f"first"`
# (19..20, 18..28) - `rf"second"`
crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs
Outdated
Show resolved
Hide resolved
crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs
Outdated
Show resolved
Hide resolved
crates/ruff/src/rules/pyflakes/rules/f_string_missing_placeholders.rs
Outdated
Show resolved
Hide resolved
e53db6c to
8e92f64
Compare
37085d0 to
be4b836
Compare

Summary
This PR updates the
F541rule to use the new f-string tokens.Test Plan
Add new test case and uncomment a broken test case.
fixes: #7292