-
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
[pylint
] Implement rule to prefer augmented assignment (PLR6104
)
#9932
[pylint
] Implement rule to prefer augmented assignment (PLR6104
)
#9932
Conversation
|
code | total | + violation | - violation | + fix | - fix |
---|---|---|---|---|---|
PLR6104 | 506 | 506 | 0 | 0 | 0 |
PLR0914 | 2 | 1 | 1 | 0 | 0 |
c3255c5
to
2241be2
Compare
CodSpeed Performance ReportMerging #9932 will not alter performanceComparing Summary
|
0bc73ac
to
6fbedf6
Compare
Not a rust dev, so I won't comment on your implementation, but I think the tests should also check for proper handling of order of operation: >>> test = 2
>>> test = test * test + 10 # OK
>>> test
14
>>> test = 2
>>> test *= test + 10
>>> test
24
>>> test = 2
>>> test = test * (test + 10) # RUF028
>>> test
24 |
Thanks for the quick reply. I added the suggested test cases. I had these two test cases in my earlier draft, but wasn’t sure and removed them. It is nice that you brought them up and have them back. |
Related pylint rule: Related issue: #970 @lshi18 instead of assigning it to RUF028, this rule should be placed under PyLint R6104. |
8bd617a
to
6e57b2c
Compare
The new rule has been moved under PLR6104 instead of RUF028. |
The |
checker: &mut Checker, | ||
assign @ ast::StmtAssign { value, targets, .. }: &ast::StmtAssign, | ||
) { | ||
if targets.len() != 1 { |
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.
Using let-else here to make this check a bit nicer:
let target = Some(targets.first()) else {
return;
}
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.
Please correct me if I am wrong, but do you mean
let Some(target) = target.first() else {
return;
}
I agree that this looks nicer if it could be changed to it.
I don't think, in this case, that they are semantically equal. In particular, the following test case which is marked as OK
fails after the suggested change.
a_number = index = a_number + 1 # OK
I think a further question would be whether we should detect the above case and, in the same gist, the one below.
index = a_number = a_number + 1 # OK
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.
My bad, I hadn't tested. Since targets is a vector, this should work:
let targets = vec![1];
// let targets = vec![1, 2];
// let targets: Vec<i32> = vec![];
let &[target] = targets.as_slice() else{
return;
};
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 had a quick test with pylint 3.0.3
, whose R6104
rule detects this
a_number = index = a_number + 1 # OK
but not this,
index = a_number = a_number + 1 # OK
Do you think we should implement to reproduce this effect?
BTW, the test cases for this rule in the pylint project include neither of the above cases, so I think the current behaviour is a side-effect of implementation.
Meanwhile, my current implementation is incorrect regarding handling more complex subsript / attribute expressions. I'll reimplement it while also taking into consideration of your other suggestions .
} | ||
let target = targets.first().unwrap(); | ||
|
||
let rhs_expr = value |
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.
let (left_operand, operator, right_operand) = Some(
value
.as_bin_op_expr()
.map(|e| (e.left.as_ref(), e.op, e.right.as_ref()))
) else {
return;
}
See let
} | ||
let (left_operand, operator, right_operand) = rhs_expr.unwrap(); | ||
|
||
if name_expr(target, left_operand) |
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.
Instead of testing these conditions, you could match the target/left_operand type with match.
There may be some other rules to serve as inspiration e.g.
ruff/crates/ruff_linter/src/rules/flake8_bugbear/rules/static_key_dict_comprehension.rs
Line 73 in 235cfb7
fn is_constant(key: &Expr, names: &FxHashMap<&str, &ast::ExprName>) -> bool { |
pylint
] Implement rule to prefer augmented assignment (PLR6104
)
840ef33
to
5afd7de
Compare
…stral-sh#9932) ## Summary Implement new rule: Prefer augmented assignment (astral-sh#8877). It checks for the assignment statement with the form of `<expr> = <expr> <binary-operator> …` with a unsafe fix to use augmented assignment instead. ## Test Plan 1. Snapshot test is included in the PR. 2. Manually test with playground.
Summary
Implement new rule: Prefer augmented assignment (#8877). It checks for the assignment statement with the form of
<expr> = <expr> <binary-operator> …
with a unsafe fix to use augmented assignment instead.Test Plan