-
Notifications
You must be signed in to change notification settings - Fork 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
[pylint] Implement consider-using-assignment-expr
(R6103
)
#13196
base: main
Are you sure you want to change the base?
[pylint] Implement consider-using-assignment-expr
(R6103
)
#13196
Conversation
CodSpeed Performance ReportMerging #13196 will not alter performanceComparing Summary
|
R6103
R6103
b422d5c
to
dbefe63
Compare
|
code | total | + violation | - violation | + fix | - fix |
---|---|---|---|---|---|
PLR6103 | 5110 | 5110 | 0 | 0 | 0 |
84c2180
to
4d891db
Compare
if checker.enabled(Rule::UnnecessaryAssignment) { | ||
pylint::rules::unnecessary_assignment(checker, if_); | ||
} |
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 applied this rule by checking whether the previous statement from a IfStmt
is an AssignStmt
, however I am wondering if it is more desirable to do check if the next statement of a AssignStmt
is an IfStmt
?
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.
What benefits do you see in testing the next statement after an AssignStmt
.
My intuition here is that there are probably more assignment than if statements. Therefore, running the rules on if nodes might overall be faster?
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 agree that assignments are far more common than if statements.
I think the answer depends on the costs for checking previous_statement
and next_statement
.
My thought here is that retrieving the previous statement using the newly added previous_statement
might be more expensive because it has to iterate over all previous statements using previous_statements
to find the previous statement (if there is a better way, please let me know).
While checking an assignment, then checking the next_statement
might be a cheap operation.
Do you have any idea? If they have equal cost I think the current implementation is fine. 😄
R6103
consider-using-assignment-expr
(R6103
)
consider-using-assignment-expr
(R6103
)consider-using-assignment-expr
(R6103
)
pub fn previous_statement(&self, stmt: &'a Stmt) -> Option<&Stmt> { | ||
self.previous_statements(stmt)?.next() | ||
} |
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 needed something like this function, not sure if there is an existing better way?
07d2997
to
964c3d6
Compare
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 for this contribution. My plane is about to land. I've to finish the review at a later time.
I only had enough time to quickly glance over the Rust code. We should look into removing the many node.clone()
calls because it is fairly expensive to clone nodes and probably unnecessary. Let me know if you need some guidance on how to remove the clone calls (It probably requires adding some lifetimes)
Regarding the rule's naming.
- I did a quick search to see how we referred to
:=
in other rules. There are not many usages butnamed expression (walrus operator)
is the most common form. - The rule name seems too generic to me and its name is very similar to
unnecessary-assign
(which we should rename to `unnecessary-assignment). Reading through the examples the rule mainly is about assigning a value that is then only used in an if condition. I need to think a bit more about what a good rule name could be. Maybe you have an idea?
bad5 = ( | ||
'example', | ||
'example', | ||
'example', | ||
'example', | ||
'example', | ||
'example', | ||
'example', | ||
'example', | ||
'example', | ||
'example', | ||
) |
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 like the example because it shows a potentially controversial use case. I would probably prefer the assignment to keep the if smaller.
crates/ruff_linter/resources/test/fixtures/pylint/unnecessary_assignment.py
Show resolved
Hide resolved
if checker.enabled(Rule::UnnecessaryAssignment) { | ||
pylint::rules::unnecessary_assignment(checker, if_); | ||
} |
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.
What benefits do you see in testing the next statement after an AssignStmt
.
My intuition here is that there are probably more assignment than if statements. Therefore, running the rules on if nodes might overall be faster?
crates/ruff_linter/src/rules/pylint/rules/unnecessary_assignment.rs
Outdated
Show resolved
Hide resolved
crates/ruff_linter/src/rules/pylint/rules/unnecessary_assignment.rs
Outdated
Show resolved
Hide resolved
Thanks for the review, much appreciated! 👍
I have tried and was able to remove almost all clone calls, except a few which I think are needed for returning the diagnostic. Could you take a look at the remaining ones and see if any of the 3 can still be removed?
I agree, here are some possible options:
These seem close to what the lint is trying to prevent, do you have other ideas in mind? |
Summary
This pull request implements the
R6103
pylint rule: pylint documentation.It checks assignments which are directly followed by if statements using that expression:
And suggest to use the
:=
operator toTest Plan
I have added test cases, and checked some of the
ruff ecosystem
results.