[pylint] Implement rule to prefer augmented assignment (PLR6104) (#9932)

## 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

1. Snapshot test is included in the PR.
2. Manually test with playground.
This commit is contained in:
wolfgangshi 2024-04-12 06:08:42 +03:00 committed by GitHub
parent 312f43475f
commit a9e4393008
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 785 additions and 0 deletions

View file

@ -0,0 +1,55 @@
# Errors
some_string = "some string"
index, a_number, to_multiply, to_divide, to_cube, timeDiffSeconds, flags = (
0,
1,
2,
3,
4,
5,
0x3,
)
a_list = [1, 2]
some_set = {"elem"}
mat1, mat2 = None, None
some_string = some_string + "a very long end of string"
index = index - 1
a_list = a_list + ["to concat"]
some_set = some_set | {"to concat"}
to_multiply = to_multiply * 5
to_divide = to_divide / 5
to_divide = to_divide // 5
to_cube = to_cube**3
to_cube = 3**to_cube
to_cube = to_cube**to_cube
timeDiffSeconds = timeDiffSeconds % 60
flags = flags & 0x1
flags = flags | 0x1
flags = flags ^ 0x1
flags = flags << 1
flags = flags >> 1
mat1 = mat1 @ mat2
a_list[1] = a_list[1] + 1
a_list[0:2] = a_list[0:2] * 3
a_list[:2] = a_list[:2] * 3
a_list[1:] = a_list[1:] * 3
a_list[:] = a_list[:] * 3
index = index * (index + 10)
class T:
def t(self):
self.a = self.a + 1
obj = T()
obj.a = obj.a + 1
# OK
a_list[0] = a_list[:] * 3
index = a_number = a_number + 1
a_number = index = a_number + 1
index = index * index + 10

View file

@ -1479,6 +1479,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
if checker.settings.rules.enabled(Rule::TypeBivariance) {
pylint::rules::type_bivariance(checker, value);
}
if checker.enabled(Rule::NonAugmentedAssignment) {
pylint::rules::non_augmented_assignment(checker, assign);
}
if checker.settings.rules.enabled(Rule::UnsortedDunderAll) {
ruff::rules::sort_dunder_all_assign(checker, assign);
}

View file

@ -293,6 +293,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "R2004") => (RuleGroup::Stable, rules::pylint::rules::MagicValueComparison),
(Pylint, "R2044") => (RuleGroup::Preview, rules::pylint::rules::EmptyComment),
(Pylint, "R5501") => (RuleGroup::Stable, rules::pylint::rules::CollapsibleElseIf),
(Pylint, "R6104") => (RuleGroup::Preview, rules::pylint::rules::NonAugmentedAssignment),
(Pylint, "R6201") => (RuleGroup::Preview, rules::pylint::rules::LiteralMembership),
#[allow(deprecated)]
(Pylint, "R6301") => (RuleGroup::Nursery, rules::pylint::rules::NoSelfUse),

View file

@ -186,6 +186,7 @@ mod tests {
Rule::UnnecessaryDictIndexLookup,
Path::new("unnecessary_dict_index_lookup.py")
)]
#[test_case(Rule::NonAugmentedAssignment, Path::new("non_augmented_assignment.py"))]
#[test_case(
Rule::UselessExceptionStatement,
Path::new("useless_exception_statement.py")

View file

@ -47,6 +47,7 @@ pub(crate) use no_method_decorator::*;
pub(crate) use no_self_use::*;
pub(crate) use non_ascii_module_import::*;
pub(crate) use non_ascii_name::*;
pub(crate) use non_augmented_assignment::*;
pub(crate) use non_slot_assignment::*;
pub(crate) use nonlocal_and_global::*;
pub(crate) use nonlocal_without_binding::*;
@ -143,6 +144,7 @@ mod no_method_decorator;
mod no_self_use;
mod non_ascii_module_import;
mod non_ascii_name;
mod non_augmented_assignment;
mod non_slot_assignment;
mod nonlocal_and_global;
mod nonlocal_without_binding;

View file

@ -0,0 +1,202 @@
use ast::{Expr, StmtAugAssign};
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast as ast;
use ruff_python_ast::comparable::ComparableExpr;
use ruff_python_ast::Operator;
use ruff_python_codegen::Generator;
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for assignments that can be replaced with augmented assignment
/// statements.
///
/// ## Why is this bad?
/// If an assignment statement consists of a binary operation in which one
/// operand is the same as the assignment target, it can be rewritten as an
/// augmented assignment. For example, `x = x + 1` can be rewritten as
/// `x += 1`.
///
/// When performing such an operation, augmented assignments are more concise
/// and idiomatic.
///
/// ## Example
/// ```python
/// x = x + 1
/// ```
///
/// Use instead:
/// ```python
/// x += 1
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as unsafe, as augmented assignments have
/// different semantics when the target is a mutable data type, like a list or
/// dictionary.
///
/// For example, consider the following:
///
/// ```python
/// foo = [1]
/// bar = foo
/// foo = foo + [2]
/// assert (foo, bar) == ([1, 2], [1])
/// ```
///
/// If the assignment is replaced with an augmented assignment, the update
/// operation will apply to both `foo` and `bar`, as they refer to the same
/// object:
///
/// ```python
/// foo = [1]
/// bar = foo
/// foo += [2]
/// assert (foo, bar) == ([1, 2], [1, 2])
/// ```
#[violation]
pub struct NonAugmentedAssignment {
operator: AugmentedOperator,
}
impl AlwaysFixableViolation for NonAugmentedAssignment {
#[derive_message_formats]
fn message(&self) -> String {
let NonAugmentedAssignment { operator } = self;
format!("Use `{operator}` to perform an augmented assignment directly")
}
fn fix_title(&self) -> String {
"Replace with augmented assignment".to_string()
}
}
/// PLR6104
pub(crate) fn non_augmented_assignment(checker: &mut Checker, assign: &ast::StmtAssign) {
// Ignore multiple assignment targets.
let [target] = assign.targets.as_slice() else {
return;
};
// Match, e.g., `x = x + 1`.
let Expr::BinOp(value) = &*assign.value else {
return;
};
// Match, e.g., `x = x + 1`.
if ComparableExpr::from(target) == ComparableExpr::from(&value.left) {
let mut diagnostic = Diagnostic::new(
NonAugmentedAssignment {
operator: AugmentedOperator::from(value.op),
},
assign.range(),
);
diagnostic.set_fix(Fix::unsafe_edit(augmented_assignment(
checker.generator(),
target,
value.op,
&value.right,
assign.range(),
)));
checker.diagnostics.push(diagnostic);
return;
}
// Match, e.g., `x = 1 + x`.
if ComparableExpr::from(target) == ComparableExpr::from(&value.right) {
let mut diagnostic = Diagnostic::new(
NonAugmentedAssignment {
operator: AugmentedOperator::from(value.op),
},
assign.range(),
);
diagnostic.set_fix(Fix::unsafe_edit(augmented_assignment(
checker.generator(),
target,
value.op,
&value.left,
assign.range(),
)));
checker.diagnostics.push(diagnostic);
}
}
/// Generate a fix to convert an assignment statement to an augmented assignment.
///
/// For example, given `x = x + 1`, the fix would be `x += 1`.
fn augmented_assignment(
generator: Generator,
target: &Expr,
operator: Operator,
right_operand: &Expr,
range: TextRange,
) -> Edit {
Edit::range_replacement(
generator.stmt(&ast::Stmt::AugAssign(StmtAugAssign {
range: TextRange::default(),
target: Box::new(target.clone()),
op: operator,
value: Box::new(right_operand.clone()),
})),
range,
)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum AugmentedOperator {
Add,
BitAnd,
BitOr,
BitXor,
Div,
FloorDiv,
LShift,
MatMult,
Mod,
Mult,
Pow,
RShift,
Sub,
}
impl From<Operator> for AugmentedOperator {
fn from(value: Operator) -> Self {
match value {
Operator::Add => Self::Add,
Operator::BitAnd => Self::BitAnd,
Operator::BitOr => Self::BitOr,
Operator::BitXor => Self::BitXor,
Operator::Div => Self::Div,
Operator::FloorDiv => Self::FloorDiv,
Operator::LShift => Self::LShift,
Operator::MatMult => Self::MatMult,
Operator::Mod => Self::Mod,
Operator::Mult => Self::Mult,
Operator::Pow => Self::Pow,
Operator::RShift => Self::RShift,
Operator::Sub => Self::Sub,
}
}
}
impl std::fmt::Display for AugmentedOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Add => f.write_str("+="),
Self::BitAnd => f.write_str("&="),
Self::BitOr => f.write_str("|="),
Self::BitXor => f.write_str("^="),
Self::Div => f.write_str("/="),
Self::FloorDiv => f.write_str("//="),
Self::LShift => f.write_str("<<="),
Self::MatMult => f.write_str("@="),
Self::Mod => f.write_str("%="),
Self::Mult => f.write_str("*="),
Self::Pow => f.write_str("**="),
Self::RShift => f.write_str(">>="),
Self::Sub => f.write_str("-="),
}
}
}

View file

@ -0,0 +1,518 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---
non_augmented_assignment.py:16:1: PLR6104 [*] Use `+=` to perform an augmented assignment directly
|
14 | mat1, mat2 = None, None
15 |
16 | some_string = some_string + "a very long end of string"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
17 | index = index - 1
18 | a_list = a_list + ["to concat"]
|
= help: Replace with augmented assignment
Unsafe fix
13 13 | some_set = {"elem"}
14 14 | mat1, mat2 = None, None
15 15 |
16 |-some_string = some_string + "a very long end of string"
16 |+some_string += "a very long end of string"
17 17 | index = index - 1
18 18 | a_list = a_list + ["to concat"]
19 19 | some_set = some_set | {"to concat"}
non_augmented_assignment.py:17:1: PLR6104 [*] Use `-=` to perform an augmented assignment directly
|
16 | some_string = some_string + "a very long end of string"
17 | index = index - 1
| ^^^^^^^^^^^^^^^^^ PLR6104
18 | a_list = a_list + ["to concat"]
19 | some_set = some_set | {"to concat"}
|
= help: Replace with augmented assignment
Unsafe fix
14 14 | mat1, mat2 = None, None
15 15 |
16 16 | some_string = some_string + "a very long end of string"
17 |-index = index - 1
17 |+index -= 1
18 18 | a_list = a_list + ["to concat"]
19 19 | some_set = some_set | {"to concat"}
20 20 | to_multiply = to_multiply * 5
non_augmented_assignment.py:18:1: PLR6104 [*] Use `+=` to perform an augmented assignment directly
|
16 | some_string = some_string + "a very long end of string"
17 | index = index - 1
18 | a_list = a_list + ["to concat"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
19 | some_set = some_set | {"to concat"}
20 | to_multiply = to_multiply * 5
|
= help: Replace with augmented assignment
Unsafe fix
15 15 |
16 16 | some_string = some_string + "a very long end of string"
17 17 | index = index - 1
18 |-a_list = a_list + ["to concat"]
18 |+a_list += ["to concat"]
19 19 | some_set = some_set | {"to concat"}
20 20 | to_multiply = to_multiply * 5
21 21 | to_divide = to_divide / 5
non_augmented_assignment.py:19:1: PLR6104 [*] Use `|=` to perform an augmented assignment directly
|
17 | index = index - 1
18 | a_list = a_list + ["to concat"]
19 | some_set = some_set | {"to concat"}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
20 | to_multiply = to_multiply * 5
21 | to_divide = to_divide / 5
|
= help: Replace with augmented assignment
Unsafe fix
16 16 | some_string = some_string + "a very long end of string"
17 17 | index = index - 1
18 18 | a_list = a_list + ["to concat"]
19 |-some_set = some_set | {"to concat"}
19 |+some_set |= {"to concat"}
20 20 | to_multiply = to_multiply * 5
21 21 | to_divide = to_divide / 5
22 22 | to_divide = to_divide // 5
non_augmented_assignment.py:20:1: PLR6104 [*] Use `*=` to perform an augmented assignment directly
|
18 | a_list = a_list + ["to concat"]
19 | some_set = some_set | {"to concat"}
20 | to_multiply = to_multiply * 5
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
21 | to_divide = to_divide / 5
22 | to_divide = to_divide // 5
|
= help: Replace with augmented assignment
Unsafe fix
17 17 | index = index - 1
18 18 | a_list = a_list + ["to concat"]
19 19 | some_set = some_set | {"to concat"}
20 |-to_multiply = to_multiply * 5
20 |+to_multiply *= 5
21 21 | to_divide = to_divide / 5
22 22 | to_divide = to_divide // 5
23 23 | to_cube = to_cube**3
non_augmented_assignment.py:21:1: PLR6104 [*] Use `/=` to perform an augmented assignment directly
|
19 | some_set = some_set | {"to concat"}
20 | to_multiply = to_multiply * 5
21 | to_divide = to_divide / 5
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
22 | to_divide = to_divide // 5
23 | to_cube = to_cube**3
|
= help: Replace with augmented assignment
Unsafe fix
18 18 | a_list = a_list + ["to concat"]
19 19 | some_set = some_set | {"to concat"}
20 20 | to_multiply = to_multiply * 5
21 |-to_divide = to_divide / 5
21 |+to_divide /= 5
22 22 | to_divide = to_divide // 5
23 23 | to_cube = to_cube**3
24 24 | to_cube = 3**to_cube
non_augmented_assignment.py:22:1: PLR6104 [*] Use `//=` to perform an augmented assignment directly
|
20 | to_multiply = to_multiply * 5
21 | to_divide = to_divide / 5
22 | to_divide = to_divide // 5
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
23 | to_cube = to_cube**3
24 | to_cube = 3**to_cube
|
= help: Replace with augmented assignment
Unsafe fix
19 19 | some_set = some_set | {"to concat"}
20 20 | to_multiply = to_multiply * 5
21 21 | to_divide = to_divide / 5
22 |-to_divide = to_divide // 5
22 |+to_divide //= 5
23 23 | to_cube = to_cube**3
24 24 | to_cube = 3**to_cube
25 25 | to_cube = to_cube**to_cube
non_augmented_assignment.py:23:1: PLR6104 [*] Use `**=` to perform an augmented assignment directly
|
21 | to_divide = to_divide / 5
22 | to_divide = to_divide // 5
23 | to_cube = to_cube**3
| ^^^^^^^^^^^^^^^^^^^^ PLR6104
24 | to_cube = 3**to_cube
25 | to_cube = to_cube**to_cube
|
= help: Replace with augmented assignment
Unsafe fix
20 20 | to_multiply = to_multiply * 5
21 21 | to_divide = to_divide / 5
22 22 | to_divide = to_divide // 5
23 |-to_cube = to_cube**3
23 |+to_cube **= 3
24 24 | to_cube = 3**to_cube
25 25 | to_cube = to_cube**to_cube
26 26 | timeDiffSeconds = timeDiffSeconds % 60
non_augmented_assignment.py:24:1: PLR6104 [*] Use `**=` to perform an augmented assignment directly
|
22 | to_divide = to_divide // 5
23 | to_cube = to_cube**3
24 | to_cube = 3**to_cube
| ^^^^^^^^^^^^^^^^^^^^ PLR6104
25 | to_cube = to_cube**to_cube
26 | timeDiffSeconds = timeDiffSeconds % 60
|
= help: Replace with augmented assignment
Unsafe fix
21 21 | to_divide = to_divide / 5
22 22 | to_divide = to_divide // 5
23 23 | to_cube = to_cube**3
24 |-to_cube = 3**to_cube
24 |+to_cube **= 3
25 25 | to_cube = to_cube**to_cube
26 26 | timeDiffSeconds = timeDiffSeconds % 60
27 27 | flags = flags & 0x1
non_augmented_assignment.py:25:1: PLR6104 [*] Use `**=` to perform an augmented assignment directly
|
23 | to_cube = to_cube**3
24 | to_cube = 3**to_cube
25 | to_cube = to_cube**to_cube
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
26 | timeDiffSeconds = timeDiffSeconds % 60
27 | flags = flags & 0x1
|
= help: Replace with augmented assignment
Unsafe fix
22 22 | to_divide = to_divide // 5
23 23 | to_cube = to_cube**3
24 24 | to_cube = 3**to_cube
25 |-to_cube = to_cube**to_cube
25 |+to_cube **= to_cube
26 26 | timeDiffSeconds = timeDiffSeconds % 60
27 27 | flags = flags & 0x1
28 28 | flags = flags | 0x1
non_augmented_assignment.py:26:1: PLR6104 [*] Use `%=` to perform an augmented assignment directly
|
24 | to_cube = 3**to_cube
25 | to_cube = to_cube**to_cube
26 | timeDiffSeconds = timeDiffSeconds % 60
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
27 | flags = flags & 0x1
28 | flags = flags | 0x1
|
= help: Replace with augmented assignment
Unsafe fix
23 23 | to_cube = to_cube**3
24 24 | to_cube = 3**to_cube
25 25 | to_cube = to_cube**to_cube
26 |-timeDiffSeconds = timeDiffSeconds % 60
26 |+timeDiffSeconds %= 60
27 27 | flags = flags & 0x1
28 28 | flags = flags | 0x1
29 29 | flags = flags ^ 0x1
non_augmented_assignment.py:27:1: PLR6104 [*] Use `&=` to perform an augmented assignment directly
|
25 | to_cube = to_cube**to_cube
26 | timeDiffSeconds = timeDiffSeconds % 60
27 | flags = flags & 0x1
| ^^^^^^^^^^^^^^^^^^^ PLR6104
28 | flags = flags | 0x1
29 | flags = flags ^ 0x1
|
= help: Replace with augmented assignment
Unsafe fix
24 24 | to_cube = 3**to_cube
25 25 | to_cube = to_cube**to_cube
26 26 | timeDiffSeconds = timeDiffSeconds % 60
27 |-flags = flags & 0x1
27 |+flags &= 1
28 28 | flags = flags | 0x1
29 29 | flags = flags ^ 0x1
30 30 | flags = flags << 1
non_augmented_assignment.py:28:1: PLR6104 [*] Use `|=` to perform an augmented assignment directly
|
26 | timeDiffSeconds = timeDiffSeconds % 60
27 | flags = flags & 0x1
28 | flags = flags | 0x1
| ^^^^^^^^^^^^^^^^^^^ PLR6104
29 | flags = flags ^ 0x1
30 | flags = flags << 1
|
= help: Replace with augmented assignment
Unsafe fix
25 25 | to_cube = to_cube**to_cube
26 26 | timeDiffSeconds = timeDiffSeconds % 60
27 27 | flags = flags & 0x1
28 |-flags = flags | 0x1
28 |+flags |= 1
29 29 | flags = flags ^ 0x1
30 30 | flags = flags << 1
31 31 | flags = flags >> 1
non_augmented_assignment.py:29:1: PLR6104 [*] Use `^=` to perform an augmented assignment directly
|
27 | flags = flags & 0x1
28 | flags = flags | 0x1
29 | flags = flags ^ 0x1
| ^^^^^^^^^^^^^^^^^^^ PLR6104
30 | flags = flags << 1
31 | flags = flags >> 1
|
= help: Replace with augmented assignment
Unsafe fix
26 26 | timeDiffSeconds = timeDiffSeconds % 60
27 27 | flags = flags & 0x1
28 28 | flags = flags | 0x1
29 |-flags = flags ^ 0x1
29 |+flags ^= 1
30 30 | flags = flags << 1
31 31 | flags = flags >> 1
32 32 | mat1 = mat1 @ mat2
non_augmented_assignment.py:30:1: PLR6104 [*] Use `<<=` to perform an augmented assignment directly
|
28 | flags = flags | 0x1
29 | flags = flags ^ 0x1
30 | flags = flags << 1
| ^^^^^^^^^^^^^^^^^^ PLR6104
31 | flags = flags >> 1
32 | mat1 = mat1 @ mat2
|
= help: Replace with augmented assignment
Unsafe fix
27 27 | flags = flags & 0x1
28 28 | flags = flags | 0x1
29 29 | flags = flags ^ 0x1
30 |-flags = flags << 1
30 |+flags <<= 1
31 31 | flags = flags >> 1
32 32 | mat1 = mat1 @ mat2
33 33 | a_list[1] = a_list[1] + 1
non_augmented_assignment.py:31:1: PLR6104 [*] Use `>>=` to perform an augmented assignment directly
|
29 | flags = flags ^ 0x1
30 | flags = flags << 1
31 | flags = flags >> 1
| ^^^^^^^^^^^^^^^^^^ PLR6104
32 | mat1 = mat1 @ mat2
33 | a_list[1] = a_list[1] + 1
|
= help: Replace with augmented assignment
Unsafe fix
28 28 | flags = flags | 0x1
29 29 | flags = flags ^ 0x1
30 30 | flags = flags << 1
31 |-flags = flags >> 1
31 |+flags >>= 1
32 32 | mat1 = mat1 @ mat2
33 33 | a_list[1] = a_list[1] + 1
34 34 |
non_augmented_assignment.py:32:1: PLR6104 [*] Use `@=` to perform an augmented assignment directly
|
30 | flags = flags << 1
31 | flags = flags >> 1
32 | mat1 = mat1 @ mat2
| ^^^^^^^^^^^^^^^^^^ PLR6104
33 | a_list[1] = a_list[1] + 1
|
= help: Replace with augmented assignment
Unsafe fix
29 29 | flags = flags ^ 0x1
30 30 | flags = flags << 1
31 31 | flags = flags >> 1
32 |-mat1 = mat1 @ mat2
32 |+mat1 @= mat2
33 33 | a_list[1] = a_list[1] + 1
34 34 |
35 35 | a_list[0:2] = a_list[0:2] * 3
non_augmented_assignment.py:33:1: PLR6104 [*] Use `+=` to perform an augmented assignment directly
|
31 | flags = flags >> 1
32 | mat1 = mat1 @ mat2
33 | a_list[1] = a_list[1] + 1
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
34 |
35 | a_list[0:2] = a_list[0:2] * 3
|
= help: Replace with augmented assignment
Unsafe fix
30 30 | flags = flags << 1
31 31 | flags = flags >> 1
32 32 | mat1 = mat1 @ mat2
33 |-a_list[1] = a_list[1] + 1
33 |+a_list[1] += 1
34 34 |
35 35 | a_list[0:2] = a_list[0:2] * 3
36 36 | a_list[:2] = a_list[:2] * 3
non_augmented_assignment.py:35:1: PLR6104 [*] Use `*=` to perform an augmented assignment directly
|
33 | a_list[1] = a_list[1] + 1
34 |
35 | a_list[0:2] = a_list[0:2] * 3
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
36 | a_list[:2] = a_list[:2] * 3
37 | a_list[1:] = a_list[1:] * 3
|
= help: Replace with augmented assignment
Unsafe fix
32 32 | mat1 = mat1 @ mat2
33 33 | a_list[1] = a_list[1] + 1
34 34 |
35 |-a_list[0:2] = a_list[0:2] * 3
35 |+a_list[0:2] *= 3
36 36 | a_list[:2] = a_list[:2] * 3
37 37 | a_list[1:] = a_list[1:] * 3
38 38 | a_list[:] = a_list[:] * 3
non_augmented_assignment.py:36:1: PLR6104 [*] Use `*=` to perform an augmented assignment directly
|
35 | a_list[0:2] = a_list[0:2] * 3
36 | a_list[:2] = a_list[:2] * 3
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
37 | a_list[1:] = a_list[1:] * 3
38 | a_list[:] = a_list[:] * 3
|
= help: Replace with augmented assignment
Unsafe fix
33 33 | a_list[1] = a_list[1] + 1
34 34 |
35 35 | a_list[0:2] = a_list[0:2] * 3
36 |-a_list[:2] = a_list[:2] * 3
36 |+a_list[:2] *= 3
37 37 | a_list[1:] = a_list[1:] * 3
38 38 | a_list[:] = a_list[:] * 3
39 39 |
non_augmented_assignment.py:37:1: PLR6104 [*] Use `*=` to perform an augmented assignment directly
|
35 | a_list[0:2] = a_list[0:2] * 3
36 | a_list[:2] = a_list[:2] * 3
37 | a_list[1:] = a_list[1:] * 3
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
38 | a_list[:] = a_list[:] * 3
|
= help: Replace with augmented assignment
Unsafe fix
34 34 |
35 35 | a_list[0:2] = a_list[0:2] * 3
36 36 | a_list[:2] = a_list[:2] * 3
37 |-a_list[1:] = a_list[1:] * 3
37 |+a_list[1:] *= 3
38 38 | a_list[:] = a_list[:] * 3
39 39 |
40 40 | index = index * (index + 10)
non_augmented_assignment.py:38:1: PLR6104 [*] Use `*=` to perform an augmented assignment directly
|
36 | a_list[:2] = a_list[:2] * 3
37 | a_list[1:] = a_list[1:] * 3
38 | a_list[:] = a_list[:] * 3
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
39 |
40 | index = index * (index + 10)
|
= help: Replace with augmented assignment
Unsafe fix
35 35 | a_list[0:2] = a_list[0:2] * 3
36 36 | a_list[:2] = a_list[:2] * 3
37 37 | a_list[1:] = a_list[1:] * 3
38 |-a_list[:] = a_list[:] * 3
38 |+a_list[:] *= 3
39 39 |
40 40 | index = index * (index + 10)
41 41 |
non_augmented_assignment.py:40:1: PLR6104 [*] Use `*=` to perform an augmented assignment directly
|
38 | a_list[:] = a_list[:] * 3
39 |
40 | index = index * (index + 10)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLR6104
|
= help: Replace with augmented assignment
Unsafe fix
37 37 | a_list[1:] = a_list[1:] * 3
38 38 | a_list[:] = a_list[:] * 3
39 39 |
40 |-index = index * (index + 10)
40 |+index *= index + 10
41 41 |
42 42 |
43 43 | class T:
non_augmented_assignment.py:45:9: PLR6104 [*] Use `+=` to perform an augmented assignment directly
|
43 | class T:
44 | def t(self):
45 | self.a = self.a + 1
| ^^^^^^^^^^^^^^^^^^^ PLR6104
|
= help: Replace with augmented assignment
Unsafe fix
42 42 |
43 43 | class T:
44 44 | def t(self):
45 |- self.a = self.a + 1
45 |+ self.a += 1
46 46 |
47 47 |
48 48 | obj = T()
non_augmented_assignment.py:49:1: PLR6104 [*] Use `+=` to perform an augmented assignment directly
|
48 | obj = T()
49 | obj.a = obj.a + 1
| ^^^^^^^^^^^^^^^^^ PLR6104
50 |
51 | # OK
|
= help: Replace with augmented assignment
Unsafe fix
46 46 |
47 47 |
48 48 | obj = T()
49 |-obj.a = obj.a + 1
49 |+obj.a += 1
50 50 |
51 51 | # OK
52 52 | a_list[0] = a_list[:] * 3

3
ruff.schema.json generated
View file

@ -3371,6 +3371,9 @@
"PLR550",
"PLR5501",
"PLR6",
"PLR61",
"PLR610",
"PLR6104",
"PLR62",
"PLR620",
"PLR6201",