-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[refurb
] Fix FURB103
fixes
#20790
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
base: main
Are you sure you want to change the base?
[refurb
] Fix FURB103
fixes
#20790
Conversation
|
code | total | + violation | - violation | + fix | - fix |
---|---|---|---|---|---|
FURB103 | 20 | 10 | 10 | 0 | 0 |
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.
Wow, thank you! I should have noticed this in the ecosystem check from the previous PR. Thanks for following up!
This fix obviously works and even seems a bit simpler than the old code, but I'm a bit confused how we were ending up in this state.
node_index: ruff_python_ast::AtomicNodeIndex::NONE, | ||
}; | ||
generator.expr(&call.into()) | ||
fn make_suggestion(open: &FileOpen<'_>, arg: &Expr, locator: &Locator) -> String { |
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.
If I'm following this correctly, the bug is that we're relocating the argument to a function call within the f.write
call when we're supposed to be relocating the argument to f.write
itself. Is that accurate?
If so, it seems like the root problem might actually be the arg
we're passing here and extracting in match_write_call
. It doesn't seem like we should be rewriting the arguments to json.dumps
at all.
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 didn't quite get it, but in make_suggestion
we actually just cut the source code for the argument (locator.slice(arg.range())) and put it directly, condition with open.keywords is needed to keep all arguments with names that were passed to the original open(...)
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.
The issue here is that the generator emits the arguments (and keyword arguments) in source order. See here
ruff/crates/ruff_python_codegen/src/generator.rs
Lines 1191 to 1209 in 48ada2d
for arg_or_keyword in arguments.arguments_source_order() { | |
match arg_or_keyword { | |
ArgOrKeyword::Arg(arg) => { | |
self.p_delim(&mut first, ", "); | |
self.unparse_expr(arg, precedence::COMMA); | |
} | |
ArgOrKeyword::Keyword(keyword) => { | |
self.p_delim(&mut first, ", "); | |
if let Some(arg) = &keyword.arg { | |
self.p_id(arg); | |
self.p("="); | |
self.unparse_expr(&keyword.value, precedence::COMMA); | |
} else { | |
self.p("**"); | |
self.unparse_expr(&keyword.value, precedence::MAX); | |
} | |
} | |
} | |
} |
This is obviously very surprising and probably another reason why we should change arguments
to be a single vec containing both keywoard and normal arguments, so that we don't have to do this guessing game inside generator.
For this rule, I think the fix is to use a more proper range for arg
that isn't TextRange::default
and ensures that the argument comes in the right order.
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.
The issue here is that the generator emits the arguments (and keyword arguments) in source order. See here
ruff/crates/ruff_python_codegen/src/generator.rs
Lines 1191 to 1209 in 48ada2d
for arg_or_keyword in arguments.arguments_source_order() { match arg_or_keyword { ArgOrKeyword::Arg(arg) => { self.p_delim(&mut first, ", "); self.unparse_expr(arg, precedence::COMMA); } ArgOrKeyword::Keyword(keyword) => { self.p_delim(&mut first, ", "); if let Some(arg) = &keyword.arg { self.p_id(arg); self.p("="); self.unparse_expr(&keyword.value, precedence::COMMA); } else { self.p("**"); self.unparse_expr(&keyword.value, precedence::MAX); } } } } This is obviously very surprising and probably another reason why we should change
arguments
to be a single vec containing both keywoard and normal arguments, so that we don't have to do this guessing game inside generator.For this rule, I think the fix is to use a more proper range for
arg
that isn'tTextRange::default
and ensures that the argument comes in the right order.
I think this solution should be optimal, since we get rid of AST transformations and arg.clone()
, and we also preserve the original spaces, please correct if this is wrong

Fixes #20785