-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's also unclear to me where the filtering out of f-strings without placeholders happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
F541
rule to use the new f-string tokens.Test Plan
Add new test case and uncomment a broken test case.
fixes: #7292