From d582ffd8e181b7eb9e2a5c1198896322b065283c Mon Sep 17 00:00:00 2001 From: Avasam Date: Sat, 25 Jul 2026 22:06:48 -0400 Subject: [PATCH 1/2] [`pylint`] Flag chained associative operators (`PLR6104`) Only two-operand assignments were matched, so `x = x * 2 * y` and `x = 2 * 3 * x` were missed. Python parses `a * b * c` as `(a * b) * c`, so the target is found by walking the chain's left spine. Chains are only rewritten for operators that are both commutative and associative. `@` is associative but excluded: `x @= a @ b` builds the full matrix-matrix product first, which can cost orders of magnitude more than the pair of matrix-vector products it replaces. A multi-line operand may only have been valid because the whole assigned value was parenthesized, and those parentheses are dropped with the rest of the statement, so the fix adds its own. This also corrects existing broken output for implicitly concatenated strings. Documents three fix hazards that were previously unstated: comment loss, float regrouping, and NumPy in-place operators rejecting shape or dtype changes that the plain form allows. Closes #11656 Relates to #27051 Expand rule safety recommendations for #12890 Co-Authored-By: Claude Opus 5 (1M context) --- .../pylint/non_augmented_assignment.py | 134 ++ .../pylint/rules/non_augmented_assignment.rs | 222 ++- ...__PLR6104_non_augmented_assignment.py.snap | 1316 +++++++++++++---- 3 files changed, 1316 insertions(+), 356 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/pylint/non_augmented_assignment.py b/crates/ruff_linter/resources/test/fixtures/pylint/non_augmented_assignment.py index ed4fac06d3f45f..6aac5d71256b55 100644 --- a/crates/ruff_linter/resources/test/fixtures/pylint/non_augmented_assignment.py +++ b/crates/ruff_linter/resources/test/fixtures/pylint/non_augmented_assignment.py @@ -12,6 +12,7 @@ a_list = [1, 2] some_set = {"elem"} mat1, mat2 = None, None +a_float = 0.5 some_string = some_string + "a very long end of string" index = index - 1 @@ -94,9 +95,142 @@ def t(self): test8 +# Regression tests for https://github.com/astral-sh/ruff/issues/11656 +# Chains of an associative operator. +to_multiply = to_multiply * 2 * a_number * 4 +some_string = some_string + "2" + some_string + "4" +a_list = a_list + [1] + [2] +some_set = some_set | {"to"} | {"concat"} +flags = flags & 0x1 & 0x2 +flags = flags | 0x1 | 0x2 +flags = flags ^ 0x1 ^ 0x2 +index = index + 1 + 2 + 3 + 4 +index = index * (index + 10) * 2 +to_multiply = to_multiply * 2 * (a_number + 1) +index = index \ + + 1 \ + + 2 + +# A parenthesized group of the same operator is an operand of the chain, not a link in it, so it +# stays grouped. +index = index + 1 + (2 + 3) + 4 + +# Targets that aren't a plain name, including one spread over several lines. +a_list[1] = a_list[1] + 1 + 2 +a_list[ + 1 +] = a_list[ + 1 +] + 2 + 3 + +# Parentheses around the target don't reach the AST, so the comparison against the assignment +# target still matches. +index = (index) + 1 + 2 + +# In a chain, the operands that stay on the right-hand side keep their order, so a side effect in +# one of them still runs exactly once, at the same point in the evaluation. +to_multiply = to_multiply * (a_number := 2) * 3 + +# Floating-point addition is not associative, so this fix can change the last bits of the result. +# It is reported anyway, in line with the rest of the rule's unsafe fixes. +a_float = a_float + 0.1 + 0.2 + +# `**` is right-associative, so `to_cube**2**3` is `to_cube ** (2**3)`: not a chain at all, but a +# single operation whose left operand happens to be the target. +to_cube = to_cube**2**3 + +# The parentheses that keep these continuation lines legal are dropped along with the rest of the +# statement, so the fix has to add its own. +index = ( + index + + 1 + + 2 +) +index = ( + index + + 1 # a comment inside the chain + + 2 +) +to_multiply = ( + to_multiply + * 2 + * (a_number + 1) +) +index = ( + 1 + + 2 + + index +) +some_string = ( + some_string + + "implicitly" + "concatenated" +) + +# Chains where the target is the rightmost operand, and every other operand is a number. +to_multiply = 2 * 3 * to_multiply +index = 1 + 2 + index +index = 1 + 2 * 3 + index +to_multiply = 2 * 3 * 4 * to_multiply +flags = 0x1 | 0x2 | flags + +# Unary `+`, `-` and `~` applied to a number still give a number. +index = -1 + index +index = -1 + -2 + index +to_multiply = +2 * -3 * to_multiply +flags = ~0x1 | 0x2 | flags + + +class U: + def u(self): + self.a = self.a + 1 + 2 + + # OK a_list[0] = a_list[:] * 3 index = a_number = a_number + 1 a_number = index = a_number + 1 index = index * index + 10 some_string = "a very long start to the string" + some_string + +# Chains of a non-associative operator: `x = x - 1 - 2` is not `x -= 1 - 2`. +index = index - 1 - 2 +to_divide = to_divide / 5 / 2 +to_divide = to_divide // 5 // 2 +timeDiffSeconds = timeDiffSeconds % 60 % 7 +flags = flags << 1 << 2 +flags = flags >> 1 >> 2 + +# Matrix multiplication is associative, but regrouping it can change the cost by orders of +# magnitude, so `@` chains are left alone. +mat1 = mat1 @ mat2 @ mat2 + +# Mixed operators, where the target is not the leftmost operand of the outermost operation. +index = index * 2 + 3 +index = index + 1 - 2 + +# Parenthesized chains: the parentheses sit in the middle of the text we'd reuse for the fix. The +# second case has them below the outermost operation, where the walk down the left spine has to stop +# just as it does at the top. +to_multiply = (to_multiply * 2) * 4 +index = (index + 1) + 2 + 3 + +# The target is the rightmost operand, but the operator is not commutative. +index = 1 - 2 - index +to_divide = 1 / 2 / to_divide + +# The target is the rightmost operand, but the other operands are not all numbers, so the operator +# may not be commutative here. A unary operator doesn't make its operand a number: `-a_number` is +# whatever `a_number.__neg__` returns. +to_multiply = 2 * a_number * to_multiply +some_string = "a" + "b" + some_string +to_multiply = -a_number * 2 * to_multiply +index = -a_number + index +flags = ~a_number | 0x2 | flags + +# `not 0` is a number too, but `not` is left out of the numeric-literal check: it only reaches this +# position when parenthesized, since `not 0 + index` parses as `not (0 + index)`. +index = (not 0) + index + +# The target is in the middle of the chain; rewriting would require reordering the operands. +to_multiply = 2 * to_multiply * 3 diff --git a/crates/ruff_linter/src/rules/pylint/rules/non_augmented_assignment.rs b/crates/ruff_linter/src/rules/pylint/rules/non_augmented_assignment.rs index cbe51cdd8d24ff..c296f71e6c0921 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/non_augmented_assignment.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/non_augmented_assignment.rs @@ -2,8 +2,9 @@ use ast::Expr; use ruff_macros::{ViolationMetadata, derive_message_formats}; use ruff_python_ast as ast; use ruff_python_ast::comparable::ComparableExpr; -use ruff_python_ast::token::parenthesized_range; +use ruff_python_ast::token::{Tokens, parenthesized_range}; use ruff_python_ast::{ExprBinOp, ExprRef, Operator}; +use ruff_source_file::LineRanges; use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; @@ -22,6 +23,10 @@ use crate::{AlwaysFixableViolation, Edit, Fix}; /// When performing such an operation, an augmented assignment is more concise /// and idiomatic. /// +/// The same applies to chains of the same operator, as long as the operator is +/// commutative and associative: `x = x * 2 * y` can be rewritten as +/// `x *= 2 * y`. +/// /// ## Known problems /// In some cases, this rule will not detect assignments in which the target /// is on the right-hand side of a binary operation (e.g., `x = y + x`, as @@ -34,14 +39,21 @@ use crate::{AlwaysFixableViolation, Edit, Fix}; /// If the type of the left-hand side cannot be trivially inferred, the rule /// will ignore the assignment. /// +/// Matrix multiplication (`@`) chains are deliberately left alone. `@` is +/// associative, but the grouping determines how much work is done: for a +/// vector `x`, `(x @ a) @ b` is a pair of cheap matrix-vector products, while +/// `x @= a @ b` builds the full matrix-matrix product `a @ b` first. +/// /// ## Example /// ```python /// x = x + 1 +/// y = y * 2 * z /// ``` /// /// Use instead: /// ```python /// x += 1 +/// y *= 2 * z /// ``` /// /// ## Fix safety @@ -68,6 +80,18 @@ use crate::{AlwaysFixableViolation, Edit, Fix}; /// foo += [2] /// assert (foo, bar) == ([1, 2], [1, 2]) /// ``` +/// +/// An augmented assignment can also fail where the plain form succeeds. NumPy +/// writes the result into the target's buffer, so `a *= b` raises where +/// `a = a * b` would broadcast to a new shape or promote the dtype. The same +/// applies to `a @= b`, which requires the product to have the target's shape. +/// +/// The fix replaces the whole statement, so any comments inside it are lost. +/// +/// It also regroups the operands of a chain, e.g., `x = x + y + z` becomes +/// `x += y + z`. Floating-point addition and multiplication are not +/// associative, so the result can differ in the last bits: `(0.1 + 0.2) + 0.3` +/// is not `0.1 + (0.2 + 0.3)`. #[derive(ViolationMetadata)] #[violation_metadata(preview_since = "v0.3.7")] pub(crate) struct NonAugmentedAssignment { @@ -102,65 +126,169 @@ pub(crate) fn non_augmented_assignment(checker: &Checker, assign: &ast::StmtAssi // Match, e.g., `x = x + 1`. if ComparableExpr::from(target) == ComparableExpr::from(&value.left) { - let mut diagnostic = - checker.report_diagnostic(NonAugmentedAssignment { operator }, assign.range()); - diagnostic.set_fix(Fix::unsafe_edit(augmented_assignment( + report_augmented_assignment( checker, + assign, target, operator, - &value.right, - value, - assign.range, - ))); + operand_range(checker, &value.right, value), + ); + + return; + } + + // Every remaining rewrite either moves the target to the front of the expression, or regroups + // the operands, or both, so none of them are valid unless the operands can be rearranged. + if !operator.allows_rearranging_operands() { + return; + } + + // Match a chain of the same operator, e.g., `x = x * 2 * y`. Python parses `a * b * c` as + // `(a * b) * c`, so the target sits at the bottom of the chain's left spine. + let innermost = innermost_chain_link(checker.tokens(), value); + if ComparableExpr::from(target) == ComparableExpr::from(&innermost.left) { + // Everything to the right of the target, e.g., `2 * y` in `x = x * 2 * y`. `innermost` + // sits on `value`'s left spine, so its right operand always precedes `value`'s. + let operand = FixOperand { + range: TextRange::new( + operand_range(checker, &innermost.right, innermost) + .range + .start(), + operand_range(checker, &value.right, value).range.end(), + ), + // The span covers at least two operands and the operator between them, so it is + // never a single parenthesized group. + parenthesized: false, + }; + + report_augmented_assignment(checker, assign, target, operator, operand); return; } - // If the operator is commutative, match, e.g., `x = 1 + x`, but limit such matches to primitive - // types. - if operator.is_commutative() - && (value.left.is_number_literal_expr() || value.left.is_boolean_literal_expr()) + // Match, e.g., `x = 1 + x`, but limit such matches to expressions that are guaranteed to + // evaluate to a number. Commutativity only holds for the conventional numeric meanings of these + // operators: `x = "prefix-" + x` is not `x += "prefix-"`. + // + // The left-hand side is reused verbatim, so its own grouping is preserved: this also covers + // chains such as `x = 2 * 3 * x`, which becomes `x *= 2 * 3`. + if is_numeric_constant(&value.left) && ComparableExpr::from(target) == ComparableExpr::from(&value.right) { - let mut diagnostic = - checker.report_diagnostic(NonAugmentedAssignment { operator }, assign.range()); - diagnostic.set_fix(Fix::unsafe_edit(augmented_assignment( + report_augmented_assignment( checker, + assign, target, operator, - &value.left, - value, - assign.range, - ))); + operand_range(checker, &value.left, value), + ); } } -/// Generate a fix to convert an assignment statement to an augmented assignment. +/// Walks down the left spine of `value` for as long as the nested operations use the same operator, +/// and returns the innermost one. +/// +/// For example, given `x * 2 * y` (parsed as `(x * 2) * y`), this returns `x * 2`. +/// +/// Descent stops at a parenthesized operand, e.g., `(x * 2) * y`. Those parentheses sit in the +/// middle of the source text we would otherwise reuse verbatim for the fix, so a chain that +/// contains them can't be rewritten by slicing. +fn innermost_chain_link<'a>(tokens: &Tokens, value: &'a ExprBinOp) -> &'a ExprBinOp { + let mut current = value; + + while let Expr::BinOp(left) = &*current.left + && left.op == current.op + && parenthesized_range(ExprRef::from(&*current.left), current.into(), tokens).is_none() + { + current = left; + } + + current +} + +/// Returns `true` if `expr` is a literal number or boolean, or an operation over such literals, +/// e.g. `1`, `True`, `-2`, or `2 * 3`. +/// +/// Any operator applied to numbers either produces a number or raises, so the whole expression is +/// known to be a number without having to infer any types. That includes nonsense like `2 @ 3`, +/// which is accepted here: it raises either way, so the rewrite doesn't change the behavior. +/// +/// [`ast::UnaryOp::Not`] is left out because it can only appear here parenthesized, as in +/// `x = (not 0) + x`; `not 0 + x` parses as `not (0 + x)` instead. The extra case isn't worth +/// supporting for a form nobody writes. +fn is_numeric_constant(expr: &Expr) -> bool { + match expr { + Expr::NumberLiteral(_) | Expr::BooleanLiteral(_) => true, + Expr::UnaryOp(ast::ExprUnaryOp { op, operand, .. }) => { + matches!( + op, + ast::UnaryOp::UAdd | ast::UnaryOp::USub | ast::UnaryOp::Invert + ) && is_numeric_constant(operand) + } + Expr::BinOp(ast::ExprBinOp { left, right, .. }) => { + is_numeric_constant(left) && is_numeric_constant(right) + } + _ => false, + } +} + +/// The source of the operand that becomes the right-hand side of the augmented assignment, and +/// whether that source already carries the parentheses that hold it together across line breaks. +/// +/// Depending on which form was matched, this can come from either side of the original operation: +/// `x = x + 1` takes it from the right, `x = 1 + x` from the left. +#[derive(Debug, Clone, Copy)] +struct FixOperand { + range: TextRange, + parenthesized: bool, +} + +/// Returns the source of `operand` within `parent`, including its parentheses, if any. +fn operand_range(checker: &Checker, operand: &Expr, parent: &ExprBinOp) -> FixOperand { + match parenthesized_range(ExprRef::from(operand), parent.into(), checker.tokens()) { + Some(range) => FixOperand { + range, + parenthesized: true, + }, + None => FixOperand { + range: operand.range(), + parenthesized: false, + }, + } +} + +/// Report `assign` and attach a fix that replaces the whole statement with an augmented assignment +/// of `target`, `operator` and `operand`. /// /// For example, given `x = x + 1`, the fix would be `x += 1`. -fn augmented_assignment( +fn report_augmented_assignment( checker: &Checker, + assign: &ast::StmtAssign, target: &Expr, operator: AugmentedOperator, - right_operand: &Expr, - original_expr: &ExprBinOp, - range: TextRange, -) -> Edit { + operand: FixOperand, +) { let locator = checker.locator(); - let right_operand_ref = ExprRef::from(right_operand); - let parent = original_expr.into(); - let tokens = checker.tokens(); - - let right_operand_range = - parenthesized_range(right_operand_ref, parent, tokens).unwrap_or(right_operand.range()); - let right_operand_expr = locator.slice(right_operand_range); - + let operand_expr = locator.slice(operand.range); let target_expr = locator.slice(target); - let new_content = format!("{target_expr} {operator} {right_operand_expr}"); + // A multi-line right-hand side may only have been valid because the whole assigned value was + // parenthesized, e.g. `x = (\n x\n + 1\n + 2\n)`. Those outer parentheses are dropped + // along with the rest of the statement, so put a fresh pair around the operand to keep the + // continuation lines legal. + let new_content = if operand.parenthesized || !locator.contains_line_break(operand.range) { + format!("{target_expr} {operator} {operand_expr}") + } else { + format!("{target_expr} {operator} ({operand_expr})") + }; - Edit::range_replacement(new_content, range) + let mut diagnostic = + checker.report_diagnostic(NonAugmentedAssignment { operator }, assign.range()); + diagnostic.set_fix(Fix::unsafe_edit(Edit::range_replacement( + new_content, + assign.range, + ))); } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -181,8 +309,28 @@ enum AugmentedOperator { } impl AugmentedOperator { - /// Returns `true` if the operator is commutative. - fn is_commutative(self) -> bool { + /// Returns `true` if the operands of this operator can be rearranged freely, i.e. the operator + /// is both commutative and associative. + /// + /// Commutativity is what lets `x = 1 + x` become `x += 1`; associativity is what lets + /// `x = x + y + z` become `x += y + z`. Both are needed here because the two rewrites share a + /// single guard, and every operator that has one of the properties has the other, apart from + /// [`Self::MatMult`]. If you add an operator that is associative but not commutative, or the + /// reverse, split this into two predicates rather than widening it. + /// + /// [`Self::MatMult`] is excluded even though matrix multiplication is associative, because + /// regrouping a matrix product preserves the result while potentially changing the amount of + /// arithmetic by orders of magnitude. For a vector `x`, `(x @ a) @ b` is a pair of cheap + /// matrix-vector products, while `x @= a @ b` builds the full matrix-matrix product `a @ b` + /// first. + /// + /// Note that even for the operators listed here, both properties only hold for their + /// conventional meanings. Floating-point addition and multiplication are not associative, `+` + /// on strings and lists is not commutative, and an arbitrary type can overload the operator to + /// mean anything at all. The rewrites that rely on commutativity guard against this by checking + /// that the operands are numbers; the ones that rely on associativity don't, which is why the + /// float caveat is called out in the rule's documentation. + fn allows_rearranging_operands(self) -> bool { matches!( self, Self::Add | Self::BitAnd | Self::BitOr | Self::BitXor | Self::Mult diff --git a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR6104_non_augmented_assignment.py.snap b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR6104_non_augmented_assignment.py.snap index 60f426f661c3c8..fdaa7f5be14f47 100644 --- a/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR6104_non_augmented_assignment.py.snap +++ b/crates/ruff_linter/src/rules/pylint/snapshots/ruff_linter__rules__pylint__tests__PLR6104_non_augmented_assignment.py.snap @@ -2,674 +2,1352 @@ source: crates/ruff_linter/src/rules/pylint/mod.rs --- PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:16:1 + --> non_augmented_assignment.py:17:1 | -14 | mat1, mat2 = None, None -15 | -16 | some_string = some_string + "a very long end of string" +15 | a_float = 0.5 +16 | +17 | some_string = some_string + "a very long end of string" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -17 | index = index - 1 -18 | a_list = a_list + ["to concat"] +18 | index = index - 1 +19 | a_list = a_list + ["to concat"] | help: Replace with augmented assignment | -15 | +16 | - some_string = some_string + "a very long end of string" -16 + some_string += "a very long end of string" -17 | index = index - 1 +17 + some_string += "a very long end of string" +18 | index = index - 1 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `-=` to perform an augmented assignment directly - --> non_augmented_assignment.py:17:1 + --> non_augmented_assignment.py:18:1 | -16 | some_string = some_string + "a very long end of string" -17 | index = index - 1 +17 | some_string = some_string + "a very long end of string" +18 | index = index - 1 | ^^^^^^^^^^^^^^^^^ -18 | a_list = a_list + ["to concat"] -19 | some_set = some_set | {"to concat"} +19 | a_list = a_list + ["to concat"] +20 | some_set = some_set | {"to concat"} | help: Replace with augmented assignment | -16 | some_string = some_string + "a very long end of string" +17 | some_string = some_string + "a very long end of string" - index = index - 1 -17 + index -= 1 -18 | a_list = a_list + ["to concat"] +18 + index -= 1 +19 | a_list = a_list + ["to concat"] | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:18:1 + --> non_augmented_assignment.py:19:1 | -16 | some_string = some_string + "a very long end of string" -17 | index = index - 1 -18 | a_list = a_list + ["to concat"] +17 | some_string = some_string + "a very long end of string" +18 | index = index - 1 +19 | a_list = a_list + ["to concat"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -19 | some_set = some_set | {"to concat"} -20 | to_multiply = to_multiply * 5 +20 | some_set = some_set | {"to concat"} +21 | to_multiply = to_multiply * 5 | help: Replace with augmented assignment | -17 | index = index - 1 +18 | index = index - 1 - a_list = a_list + ["to concat"] -18 + a_list += ["to concat"] -19 | some_set = some_set | {"to concat"} +19 + a_list += ["to concat"] +20 | some_set = some_set | {"to concat"} | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `|=` to perform an augmented assignment directly - --> non_augmented_assignment.py:19:1 + --> non_augmented_assignment.py:20:1 | -17 | index = index - 1 -18 | a_list = a_list + ["to concat"] -19 | some_set = some_set | {"to concat"} +18 | index = index - 1 +19 | a_list = a_list + ["to concat"] +20 | some_set = some_set | {"to concat"} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -20 | to_multiply = to_multiply * 5 -21 | to_multiply = 5 * to_multiply +21 | to_multiply = to_multiply * 5 +22 | to_multiply = 5 * to_multiply | help: Replace with augmented assignment | -18 | a_list = a_list + ["to concat"] +19 | a_list = a_list + ["to concat"] - some_set = some_set | {"to concat"} -19 + some_set |= {"to concat"} -20 | to_multiply = to_multiply * 5 +20 + some_set |= {"to concat"} +21 | to_multiply = to_multiply * 5 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `*=` to perform an augmented assignment directly - --> non_augmented_assignment.py:20:1 + --> non_augmented_assignment.py:21:1 | -18 | a_list = a_list + ["to concat"] -19 | some_set = some_set | {"to concat"} -20 | to_multiply = to_multiply * 5 +19 | a_list = a_list + ["to concat"] +20 | some_set = some_set | {"to concat"} +21 | to_multiply = to_multiply * 5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -21 | to_multiply = 5 * to_multiply -22 | to_multiply = to_multiply * to_multiply +22 | to_multiply = 5 * to_multiply +23 | to_multiply = to_multiply * to_multiply | help: Replace with augmented assignment | -19 | some_set = some_set | {"to concat"} +20 | some_set = some_set | {"to concat"} - to_multiply = to_multiply * 5 -20 + to_multiply *= 5 -21 | to_multiply = 5 * to_multiply +21 + to_multiply *= 5 +22 | to_multiply = 5 * to_multiply | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `*=` to perform an augmented assignment directly - --> non_augmented_assignment.py:21:1 + --> non_augmented_assignment.py:22:1 | -19 | some_set = some_set | {"to concat"} -20 | to_multiply = to_multiply * 5 -21 | to_multiply = 5 * to_multiply +20 | some_set = some_set | {"to concat"} +21 | to_multiply = to_multiply * 5 +22 | to_multiply = 5 * to_multiply | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -22 | to_multiply = to_multiply * to_multiply -23 | to_divide = to_divide / 5 +23 | to_multiply = to_multiply * to_multiply +24 | to_divide = to_divide / 5 | help: Replace with augmented assignment | -20 | to_multiply = to_multiply * 5 +21 | to_multiply = to_multiply * 5 - to_multiply = 5 * to_multiply -21 + to_multiply *= 5 -22 | to_multiply = to_multiply * to_multiply +22 + to_multiply *= 5 +23 | to_multiply = to_multiply * to_multiply | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `*=` to perform an augmented assignment directly - --> non_augmented_assignment.py:22:1 + --> non_augmented_assignment.py:23:1 | -20 | to_multiply = to_multiply * 5 -21 | to_multiply = 5 * to_multiply -22 | to_multiply = to_multiply * to_multiply +21 | to_multiply = to_multiply * 5 +22 | to_multiply = 5 * to_multiply +23 | to_multiply = to_multiply * to_multiply | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -23 | to_divide = to_divide / 5 -24 | to_divide = to_divide // 5 +24 | to_divide = to_divide / 5 +25 | to_divide = to_divide // 5 | help: Replace with augmented assignment | -21 | to_multiply = 5 * to_multiply +22 | to_multiply = 5 * to_multiply - to_multiply = to_multiply * to_multiply -22 + to_multiply *= to_multiply -23 | to_divide = to_divide / 5 +23 + to_multiply *= to_multiply +24 | to_divide = to_divide / 5 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `/=` to perform an augmented assignment directly - --> non_augmented_assignment.py:23:1 + --> non_augmented_assignment.py:24:1 | -21 | to_multiply = 5 * to_multiply -22 | to_multiply = to_multiply * to_multiply -23 | to_divide = to_divide / 5 +22 | to_multiply = 5 * to_multiply +23 | to_multiply = to_multiply * to_multiply +24 | to_divide = to_divide / 5 | ^^^^^^^^^^^^^^^^^^^^^^^^^ -24 | to_divide = to_divide // 5 -25 | to_cube = to_cube**3 +25 | to_divide = to_divide // 5 +26 | to_cube = to_cube**3 | help: Replace with augmented assignment | -22 | to_multiply = to_multiply * to_multiply +23 | to_multiply = to_multiply * to_multiply - to_divide = to_divide / 5 -23 + to_divide /= 5 -24 | to_divide = to_divide // 5 +24 + to_divide /= 5 +25 | to_divide = to_divide // 5 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `//=` to perform an augmented assignment directly - --> non_augmented_assignment.py:24:1 + --> non_augmented_assignment.py:25:1 | -22 | to_multiply = to_multiply * to_multiply -23 | to_divide = to_divide / 5 -24 | to_divide = to_divide // 5 +23 | to_multiply = to_multiply * to_multiply +24 | to_divide = to_divide / 5 +25 | to_divide = to_divide // 5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -25 | to_cube = to_cube**3 -26 | to_cube = 3**to_cube +26 | to_cube = to_cube**3 +27 | to_cube = 3**to_cube | help: Replace with augmented assignment | -23 | to_divide = to_divide / 5 +24 | to_divide = to_divide / 5 - to_divide = to_divide // 5 -24 + to_divide //= 5 -25 | to_cube = to_cube**3 +25 + to_divide //= 5 +26 | to_cube = to_cube**3 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `**=` to perform an augmented assignment directly - --> non_augmented_assignment.py:25:1 + --> non_augmented_assignment.py:26:1 | -23 | to_divide = to_divide / 5 -24 | to_divide = to_divide // 5 -25 | to_cube = to_cube**3 +24 | to_divide = to_divide / 5 +25 | to_divide = to_divide // 5 +26 | to_cube = to_cube**3 | ^^^^^^^^^^^^^^^^^^^^ -26 | to_cube = 3**to_cube -27 | to_cube = to_cube**to_cube +27 | to_cube = 3**to_cube +28 | to_cube = to_cube**to_cube | help: Replace with augmented assignment | -24 | to_divide = to_divide // 5 +25 | to_divide = to_divide // 5 - to_cube = to_cube**3 -25 + to_cube **= 3 -26 | to_cube = 3**to_cube +26 + to_cube **= 3 +27 | to_cube = 3**to_cube | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `**=` to perform an augmented assignment directly - --> non_augmented_assignment.py:27:1 + --> non_augmented_assignment.py:28:1 | -25 | to_cube = to_cube**3 -26 | to_cube = 3**to_cube -27 | to_cube = to_cube**to_cube +26 | to_cube = to_cube**3 +27 | to_cube = 3**to_cube +28 | to_cube = to_cube**to_cube | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -28 | timeDiffSeconds = timeDiffSeconds % 60 -29 | flags = flags & 0x1 +29 | timeDiffSeconds = timeDiffSeconds % 60 +30 | flags = flags & 0x1 | help: Replace with augmented assignment | -26 | to_cube = 3**to_cube +27 | to_cube = 3**to_cube - to_cube = to_cube**to_cube -27 + to_cube **= to_cube -28 | timeDiffSeconds = timeDiffSeconds % 60 +28 + to_cube **= to_cube +29 | timeDiffSeconds = timeDiffSeconds % 60 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `%=` to perform an augmented assignment directly - --> non_augmented_assignment.py:28:1 + --> non_augmented_assignment.py:29:1 | -26 | to_cube = 3**to_cube -27 | to_cube = to_cube**to_cube -28 | timeDiffSeconds = timeDiffSeconds % 60 +27 | to_cube = 3**to_cube +28 | to_cube = to_cube**to_cube +29 | timeDiffSeconds = timeDiffSeconds % 60 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -29 | flags = flags & 0x1 -30 | flags = flags | 0x1 +30 | flags = flags & 0x1 +31 | flags = flags | 0x1 | help: Replace with augmented assignment | -27 | to_cube = to_cube**to_cube +28 | to_cube = to_cube**to_cube - timeDiffSeconds = timeDiffSeconds % 60 -28 + timeDiffSeconds %= 60 -29 | flags = flags & 0x1 +29 + timeDiffSeconds %= 60 +30 | flags = flags & 0x1 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `&=` to perform an augmented assignment directly - --> non_augmented_assignment.py:29:1 + --> non_augmented_assignment.py:30:1 | -27 | to_cube = to_cube**to_cube -28 | timeDiffSeconds = timeDiffSeconds % 60 -29 | flags = flags & 0x1 +28 | to_cube = to_cube**to_cube +29 | timeDiffSeconds = timeDiffSeconds % 60 +30 | flags = flags & 0x1 | ^^^^^^^^^^^^^^^^^^^ -30 | flags = flags | 0x1 -31 | flags = flags ^ 0x1 +31 | flags = flags | 0x1 +32 | flags = flags ^ 0x1 | help: Replace with augmented assignment | -28 | timeDiffSeconds = timeDiffSeconds % 60 +29 | timeDiffSeconds = timeDiffSeconds % 60 - flags = flags & 0x1 -29 + flags &= 0x1 -30 | flags = flags | 0x1 +30 + flags &= 0x1 +31 | flags = flags | 0x1 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `|=` to perform an augmented assignment directly - --> non_augmented_assignment.py:30:1 + --> non_augmented_assignment.py:31:1 | -28 | timeDiffSeconds = timeDiffSeconds % 60 -29 | flags = flags & 0x1 -30 | flags = flags | 0x1 +29 | timeDiffSeconds = timeDiffSeconds % 60 +30 | flags = flags & 0x1 +31 | flags = flags | 0x1 | ^^^^^^^^^^^^^^^^^^^ -31 | flags = flags ^ 0x1 -32 | flags = flags << 1 +32 | flags = flags ^ 0x1 +33 | flags = flags << 1 | help: Replace with augmented assignment | -29 | flags = flags & 0x1 +30 | flags = flags & 0x1 - flags = flags | 0x1 -30 + flags |= 0x1 -31 | flags = flags ^ 0x1 +31 + flags |= 0x1 +32 | flags = flags ^ 0x1 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `^=` to perform an augmented assignment directly - --> non_augmented_assignment.py:31:1 + --> non_augmented_assignment.py:32:1 | -29 | flags = flags & 0x1 -30 | flags = flags | 0x1 -31 | flags = flags ^ 0x1 +30 | flags = flags & 0x1 +31 | flags = flags | 0x1 +32 | flags = flags ^ 0x1 | ^^^^^^^^^^^^^^^^^^^ -32 | flags = flags << 1 -33 | flags = flags >> 1 +33 | flags = flags << 1 +34 | flags = flags >> 1 | help: Replace with augmented assignment | -30 | flags = flags | 0x1 +31 | flags = flags | 0x1 - flags = flags ^ 0x1 -31 + flags ^= 0x1 -32 | flags = flags << 1 +32 + flags ^= 0x1 +33 | flags = flags << 1 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `<<=` to perform an augmented assignment directly - --> non_augmented_assignment.py:32:1 + --> non_augmented_assignment.py:33:1 | -30 | flags = flags | 0x1 -31 | flags = flags ^ 0x1 -32 | flags = flags << 1 +31 | flags = flags | 0x1 +32 | flags = flags ^ 0x1 +33 | flags = flags << 1 | ^^^^^^^^^^^^^^^^^^ -33 | flags = flags >> 1 -34 | mat1 = mat1 @ mat2 +34 | flags = flags >> 1 +35 | mat1 = mat1 @ mat2 | help: Replace with augmented assignment | -31 | flags = flags ^ 0x1 +32 | flags = flags ^ 0x1 - flags = flags << 1 -32 + flags <<= 1 -33 | flags = flags >> 1 +33 + flags <<= 1 +34 | flags = flags >> 1 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `>>=` to perform an augmented assignment directly - --> non_augmented_assignment.py:33:1 + --> non_augmented_assignment.py:34:1 | -31 | flags = flags ^ 0x1 -32 | flags = flags << 1 -33 | flags = flags >> 1 +32 | flags = flags ^ 0x1 +33 | flags = flags << 1 +34 | flags = flags >> 1 | ^^^^^^^^^^^^^^^^^^ -34 | mat1 = mat1 @ mat2 -35 | a_list[1] = a_list[1] + 1 +35 | mat1 = mat1 @ mat2 +36 | a_list[1] = a_list[1] + 1 | help: Replace with augmented assignment | -32 | flags = flags << 1 +33 | flags = flags << 1 - flags = flags >> 1 -33 + flags >>= 1 -34 | mat1 = mat1 @ mat2 +34 + flags >>= 1 +35 | mat1 = mat1 @ mat2 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `@=` to perform an augmented assignment directly - --> non_augmented_assignment.py:34:1 + --> non_augmented_assignment.py:35:1 | -32 | flags = flags << 1 -33 | flags = flags >> 1 -34 | mat1 = mat1 @ mat2 +33 | flags = flags << 1 +34 | flags = flags >> 1 +35 | mat1 = mat1 @ mat2 | ^^^^^^^^^^^^^^^^^^ -35 | a_list[1] = a_list[1] + 1 +36 | a_list[1] = a_list[1] + 1 | help: Replace with augmented assignment | -33 | flags = flags >> 1 +34 | flags = flags >> 1 - mat1 = mat1 @ mat2 -34 + mat1 @= mat2 -35 | a_list[1] = a_list[1] + 1 +35 + mat1 @= mat2 +36 | a_list[1] = a_list[1] + 1 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:35:1 + --> non_augmented_assignment.py:36:1 | -33 | flags = flags >> 1 -34 | mat1 = mat1 @ mat2 -35 | a_list[1] = a_list[1] + 1 +34 | flags = flags >> 1 +35 | mat1 = mat1 @ mat2 +36 | a_list[1] = a_list[1] + 1 | ^^^^^^^^^^^^^^^^^^^^^^^^^ -36 | -37 | a_list[0:2] = a_list[0:2] * 3 +37 | +38 | a_list[0:2] = a_list[0:2] * 3 | help: Replace with augmented assignment | -34 | mat1 = mat1 @ mat2 +35 | mat1 = mat1 @ mat2 - a_list[1] = a_list[1] + 1 -35 + a_list[1] += 1 -36 | +36 + a_list[1] += 1 +37 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `*=` to perform an augmented assignment directly - --> non_augmented_assignment.py:37:1 + --> non_augmented_assignment.py:38:1 | -35 | a_list[1] = a_list[1] + 1 -36 | -37 | a_list[0:2] = a_list[0:2] * 3 +36 | a_list[1] = a_list[1] + 1 +37 | +38 | a_list[0:2] = a_list[0:2] * 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -38 | a_list[:2] = a_list[:2] * 3 -39 | a_list[1:] = a_list[1:] * 3 +39 | a_list[:2] = a_list[:2] * 3 +40 | a_list[1:] = a_list[1:] * 3 | help: Replace with augmented assignment | -36 | +37 | - a_list[0:2] = a_list[0:2] * 3 -37 + a_list[0:2] *= 3 -38 | a_list[:2] = a_list[:2] * 3 +38 + a_list[0:2] *= 3 +39 | a_list[:2] = a_list[:2] * 3 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `*=` to perform an augmented assignment directly - --> non_augmented_assignment.py:38:1 + --> non_augmented_assignment.py:39:1 | -37 | a_list[0:2] = a_list[0:2] * 3 -38 | a_list[:2] = a_list[:2] * 3 +38 | a_list[0:2] = a_list[0:2] * 3 +39 | a_list[:2] = a_list[:2] * 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -39 | a_list[1:] = a_list[1:] * 3 -40 | a_list[:] = a_list[:] * 3 +40 | a_list[1:] = a_list[1:] * 3 +41 | a_list[:] = a_list[:] * 3 | help: Replace with augmented assignment | -37 | a_list[0:2] = a_list[0:2] * 3 +38 | a_list[0:2] = a_list[0:2] * 3 - a_list[:2] = a_list[:2] * 3 -38 + a_list[:2] *= 3 -39 | a_list[1:] = a_list[1:] * 3 +39 + a_list[:2] *= 3 +40 | a_list[1:] = a_list[1:] * 3 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `*=` to perform an augmented assignment directly - --> non_augmented_assignment.py:39:1 + --> non_augmented_assignment.py:40:1 | -37 | a_list[0:2] = a_list[0:2] * 3 -38 | a_list[:2] = a_list[:2] * 3 -39 | a_list[1:] = a_list[1:] * 3 +38 | a_list[0:2] = a_list[0:2] * 3 +39 | a_list[:2] = a_list[:2] * 3 +40 | a_list[1:] = a_list[1:] * 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -40 | a_list[:] = a_list[:] * 3 +41 | a_list[:] = a_list[:] * 3 | help: Replace with augmented assignment | -38 | a_list[:2] = a_list[:2] * 3 +39 | a_list[:2] = a_list[:2] * 3 - a_list[1:] = a_list[1:] * 3 -39 + a_list[1:] *= 3 -40 | a_list[:] = a_list[:] * 3 +40 + a_list[1:] *= 3 +41 | a_list[:] = a_list[:] * 3 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `*=` to perform an augmented assignment directly - --> non_augmented_assignment.py:40:1 + --> non_augmented_assignment.py:41:1 | -38 | a_list[:2] = a_list[:2] * 3 -39 | a_list[1:] = a_list[1:] * 3 -40 | a_list[:] = a_list[:] * 3 +39 | a_list[:2] = a_list[:2] * 3 +40 | a_list[1:] = a_list[1:] * 3 +41 | a_list[:] = a_list[:] * 3 | ^^^^^^^^^^^^^^^^^^^^^^^^^ -41 | -42 | index = index * (index + 10) +42 | +43 | index = index * (index + 10) | help: Replace with augmented assignment | -39 | a_list[1:] = a_list[1:] * 3 +40 | a_list[1:] = a_list[1:] * 3 - a_list[:] = a_list[:] * 3 -40 + a_list[:] *= 3 -41 | +41 + a_list[:] *= 3 +42 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `*=` to perform an augmented assignment directly - --> non_augmented_assignment.py:42:1 + --> non_augmented_assignment.py:43:1 | -40 | a_list[:] = a_list[:] * 3 -41 | -42 | index = index * (index + 10) +41 | a_list[:] = a_list[:] * 3 +42 | +43 | index = index * (index + 10) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: Replace with augmented assignment | -41 | +42 | - index = index * (index + 10) -42 + index *= (index + 10) -43 | +43 + index *= (index + 10) +44 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:47:9 + --> non_augmented_assignment.py:48:9 | -45 | class T: -46 | def t(self): -47 | self.a = self.a + 1 +46 | class T: +47 | def t(self): +48 | self.a = self.a + 1 | ^^^^^^^^^^^^^^^^^^^ | help: Replace with augmented assignment | -46 | def t(self): +47 | def t(self): - self.a = self.a + 1 -47 + self.a += 1 -48 | +48 + self.a += 1 +49 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:51:1 + --> non_augmented_assignment.py:52:1 | -50 | obj = T() -51 | obj.a = obj.a + 1 +51 | obj = T() +52 | obj.a = obj.a + 1 | ^^^^^^^^^^^^^^^^^ | help: Replace with augmented assignment | -50 | obj = T() +51 | obj = T() - obj.a = obj.a + 1 -51 + obj.a += 1 -52 | +52 + obj.a += 1 +53 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:54:1 + --> non_augmented_assignment.py:55:1 | -54 | a = a+-1 +55 | a = a+-1 | ^^^^^^^^ -55 | -56 | # Regression tests for https://github.com/astral-sh/ruff/issues/11672 +56 | +57 | # Regression tests for https://github.com/astral-sh/ruff/issues/11672 | help: Replace with augmented assignment | -53 | +54 | - a = a+-1 -54 + a += -1 -55 | +55 + a += -1 +56 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:58:1 + --> non_augmented_assignment.py:59:1 | -56 | # Regression tests for https://github.com/astral-sh/ruff/issues/11672 -57 | test = 0x5 -58 | test = test + 0xBA +57 | # Regression tests for https://github.com/astral-sh/ruff/issues/11672 +58 | test = 0x5 +59 | test = test + 0xBA | ^^^^^^^^^^^^^^^^^^ -59 | -60 | test2 = b"" +60 | +61 | test2 = b"" | help: Replace with augmented assignment | -57 | test = 0x5 +58 | test = 0x5 - test = test + 0xBA -58 + test += 0xBA -59 | +59 + test += 0xBA +60 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:61:1 + --> non_augmented_assignment.py:62:1 | -60 | test2 = b"" -61 | test2 = test2 + b"\000" +61 | test2 = b"" +62 | test2 = test2 + b"\000" | ^^^^^^^^^^^^^^^^^^^^^^^ -62 | -63 | test3 = "" +63 | +64 | test3 = "" | help: Replace with augmented assignment | -60 | test2 = b"" +61 | test2 = b"" - test2 = test2 + b"\000" -61 + test2 += b"\000" -62 | +62 + test2 += b"\000" +63 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:64:1 + --> non_augmented_assignment.py:65:1 | -63 | test3 = "" -64 | / test3 = test3 + ( a := R"" -65 | | f"oo" ) +64 | test3 = "" +65 | / test3 = test3 + ( a := R"" +66 | | f"oo" ) | |__________________________________^ -66 | -67 | test4 = [] +67 | +68 | test4 = [] | help: Replace with augmented assignment | -63 | test3 = "" +64 | test3 = "" - test3 = test3 + ( a := R"" -64 + test3 += ( a := R"" -65 | f"oo" ) +65 + test3 += ( a := R"" +66 | f"oo" ) | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:68:1 + --> non_augmented_assignment.py:69:1 | -67 | test4 = [] -68 | / test4 = test4 + ( e -69 | | for e in -70 | | range(10) -71 | | ) +68 | test4 = [] +69 | / test4 = test4 + ( e +70 | | for e in +71 | | range(10) +72 | | ) | |___________________^ -72 | -73 | test5 = test5 + ( +73 | +74 | test5 = test5 + ( | help: Replace with augmented assignment | -67 | test4 = [] +68 | test4 = [] - test4 = test4 + ( e -68 + test4 += ( e -69 | for e in +69 + test4 += (( e +70 | for e in +71 | range(10) + - ) +72 + )) +73 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:73:1 - | -71 | ) -72 | -73 | / test5 = test5 + ( -74 | | 4 -75 | | * -76 | | 10 -77 | | ) + --> non_augmented_assignment.py:74:1 + | +72 | ) +73 | +74 | / test5 = test5 + ( +75 | | 4 +76 | | * +77 | | 10 +78 | | ) | |_^ -78 | -79 | test6 = test6 + \ +79 | +80 | test6 = test6 + \ | help: Replace with augmented assignment | -72 | +73 | - test5 = test5 + ( -73 + test5 += ( -74 | 4 +74 + test5 += ( +75 | 4 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:79:1 - | -77 | ) -78 | -79 | / test6 = test6 + \ -80 | | ( -81 | | 4 -82 | | * -83 | | 10 -84 | | ) + --> non_augmented_assignment.py:80:1 + | +78 | ) +79 | +80 | / test6 = test6 + \ +81 | | ( +82 | | 4 +83 | | * +84 | | 10 +85 | | ) | |_________^ -85 | -86 | test7 = \ +86 | +87 | test7 = \ | help: Replace with augmented assignment | -78 | +79 | - test6 = test6 + \ - ( -79 + test6 += ( -80 | 4 +80 + test6 += ( +81 | 4 | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:86:1 + --> non_augmented_assignment.py:87:1 | -84 | ) -85 | -86 | / test7 = \ -87 | | 100 \ -88 | | + test7 +85 | ) +86 | +87 | / test7 = \ +88 | | 100 \ +89 | | + test7 | |___________^ -89 | -90 | test8 = \ +90 | +91 | test8 = \ | help: Replace with augmented assignment | -85 | +86 | - test7 = \ - 100 \ - + test7 -86 + test7 += 100 -87 | +87 + test7 += 100 +88 | | note: This is an unsafe fix and may change runtime behavior PLR6104 [*] Use `+=` to perform an augmented assignment directly - --> non_augmented_assignment.py:90:1 - | -88 | + test7 -89 | -90 | / test8 = \ -91 | | 886 \ -92 | | + \ -93 | | \ -94 | | test8 + --> non_augmented_assignment.py:91:1 + | +89 | + test7 +90 | +91 | / test8 = \ +92 | | 886 \ +93 | | + \ +94 | | \ +95 | | test8 | |_________^ | help: Replace with augmented assignment | -89 | +90 | - test8 = \ - 886 \ - + \ - \ - test8 -90 + test8 += 886 -91 | +91 + test8 += 886 +92 | | note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `*=` to perform an augmented assignment directly + --> non_augmented_assignment.py:100:1 + | + 98 | # Regression tests for https://github.com/astral-sh/ruff/issues/11656 + 99 | # Chains of an associative operator. +100 | to_multiply = to_multiply * 2 * a_number * 4 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +101 | some_string = some_string + "2" + some_string + "4" +102 | a_list = a_list + [1] + [2] + | +help: Replace with augmented assignment + | +99 | # Chains of an associative operator. + - to_multiply = to_multiply * 2 * a_number * 4 +100 + to_multiply *= 2 * a_number * 4 +101 | some_string = some_string + "2" + some_string + "4" + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:101:1 + | + 99 | # Chains of an associative operator. +100 | to_multiply = to_multiply * 2 * a_number * 4 +101 | some_string = some_string + "2" + some_string + "4" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +102 | a_list = a_list + [1] + [2] +103 | some_set = some_set | {"to"} | {"concat"} + | +help: Replace with augmented assignment + | +100 | to_multiply = to_multiply * 2 * a_number * 4 + - some_string = some_string + "2" + some_string + "4" +101 + some_string += "2" + some_string + "4" +102 | a_list = a_list + [1] + [2] + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:102:1 + | +100 | to_multiply = to_multiply * 2 * a_number * 4 +101 | some_string = some_string + "2" + some_string + "4" +102 | a_list = a_list + [1] + [2] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +103 | some_set = some_set | {"to"} | {"concat"} +104 | flags = flags & 0x1 & 0x2 + | +help: Replace with augmented assignment + | +101 | some_string = some_string + "2" + some_string + "4" + - a_list = a_list + [1] + [2] +102 + a_list += [1] + [2] +103 | some_set = some_set | {"to"} | {"concat"} + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `|=` to perform an augmented assignment directly + --> non_augmented_assignment.py:103:1 + | +101 | some_string = some_string + "2" + some_string + "4" +102 | a_list = a_list + [1] + [2] +103 | some_set = some_set | {"to"} | {"concat"} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +104 | flags = flags & 0x1 & 0x2 +105 | flags = flags | 0x1 | 0x2 + | +help: Replace with augmented assignment + | +102 | a_list = a_list + [1] + [2] + - some_set = some_set | {"to"} | {"concat"} +103 + some_set |= {"to"} | {"concat"} +104 | flags = flags & 0x1 & 0x2 + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `&=` to perform an augmented assignment directly + --> non_augmented_assignment.py:104:1 + | +102 | a_list = a_list + [1] + [2] +103 | some_set = some_set | {"to"} | {"concat"} +104 | flags = flags & 0x1 & 0x2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +105 | flags = flags | 0x1 | 0x2 +106 | flags = flags ^ 0x1 ^ 0x2 + | +help: Replace with augmented assignment + | +103 | some_set = some_set | {"to"} | {"concat"} + - flags = flags & 0x1 & 0x2 +104 + flags &= 0x1 & 0x2 +105 | flags = flags | 0x1 | 0x2 + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `|=` to perform an augmented assignment directly + --> non_augmented_assignment.py:105:1 + | +103 | some_set = some_set | {"to"} | {"concat"} +104 | flags = flags & 0x1 & 0x2 +105 | flags = flags | 0x1 | 0x2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +106 | flags = flags ^ 0x1 ^ 0x2 +107 | index = index + 1 + 2 + 3 + 4 + | +help: Replace with augmented assignment + | +104 | flags = flags & 0x1 & 0x2 + - flags = flags | 0x1 | 0x2 +105 + flags |= 0x1 | 0x2 +106 | flags = flags ^ 0x1 ^ 0x2 + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `^=` to perform an augmented assignment directly + --> non_augmented_assignment.py:106:1 + | +104 | flags = flags & 0x1 & 0x2 +105 | flags = flags | 0x1 | 0x2 +106 | flags = flags ^ 0x1 ^ 0x2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +107 | index = index + 1 + 2 + 3 + 4 +108 | index = index * (index + 10) * 2 + | +help: Replace with augmented assignment + | +105 | flags = flags | 0x1 | 0x2 + - flags = flags ^ 0x1 ^ 0x2 +106 + flags ^= 0x1 ^ 0x2 +107 | index = index + 1 + 2 + 3 + 4 + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:107:1 + | +105 | flags = flags | 0x1 | 0x2 +106 | flags = flags ^ 0x1 ^ 0x2 +107 | index = index + 1 + 2 + 3 + 4 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +108 | index = index * (index + 10) * 2 +109 | to_multiply = to_multiply * 2 * (a_number + 1) + | +help: Replace with augmented assignment + | +106 | flags = flags ^ 0x1 ^ 0x2 + - index = index + 1 + 2 + 3 + 4 +107 + index += 1 + 2 + 3 + 4 +108 | index = index * (index + 10) * 2 + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `*=` to perform an augmented assignment directly + --> non_augmented_assignment.py:108:1 + | +106 | flags = flags ^ 0x1 ^ 0x2 +107 | index = index + 1 + 2 + 3 + 4 +108 | index = index * (index + 10) * 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +109 | to_multiply = to_multiply * 2 * (a_number + 1) +110 | index = index \ + | +help: Replace with augmented assignment + | +107 | index = index + 1 + 2 + 3 + 4 + - index = index * (index + 10) * 2 +108 + index *= (index + 10) * 2 +109 | to_multiply = to_multiply * 2 * (a_number + 1) + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `*=` to perform an augmented assignment directly + --> non_augmented_assignment.py:109:1 + | +107 | index = index + 1 + 2 + 3 + 4 +108 | index = index * (index + 10) * 2 +109 | to_multiply = to_multiply * 2 * (a_number + 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +110 | index = index \ +111 | + 1 \ + | +help: Replace with augmented assignment + | +108 | index = index * (index + 10) * 2 + - to_multiply = to_multiply * 2 * (a_number + 1) +109 + to_multiply *= 2 * (a_number + 1) +110 | index = index \ + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:110:1 + | +108 | index = index * (index + 10) * 2 +109 | to_multiply = to_multiply * 2 * (a_number + 1) +110 | / index = index \ +111 | | + 1 \ +112 | | + 2 + | |_______^ +113 | +114 | # A parenthesized group of the same operator is an operand of the chain, not a link in it, so it + | +help: Replace with augmented assignment + | +109 | to_multiply = to_multiply * 2 * (a_number + 1) + - index = index \ + - + 1 \ + - + 2 +110 + index += (1 \ +111 + + 2) +112 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:116:1 + | +114 | # A parenthesized group of the same operator is an operand of the chain, not a link in it, so it +115 | # stays grouped. +116 | index = index + 1 + (2 + 3) + 4 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +117 | +118 | # Targets that aren't a plain name, including one spread over several lines. + | +help: Replace with augmented assignment + | +115 | # stays grouped. + - index = index + 1 + (2 + 3) + 4 +116 + index += 1 + (2 + 3) + 4 +117 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:119:1 + | +118 | # Targets that aren't a plain name, including one spread over several lines. +119 | a_list[1] = a_list[1] + 1 + 2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +120 | a_list[ +121 | 1 + | +help: Replace with augmented assignment + | +118 | # Targets that aren't a plain name, including one spread over several lines. + - a_list[1] = a_list[1] + 1 + 2 +119 + a_list[1] += 1 + 2 +120 | a_list[ + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:120:1 + | +118 | # Targets that aren't a plain name, including one spread over several lines. +119 | a_list[1] = a_list[1] + 1 + 2 +120 | / a_list[ +121 | | 1 +122 | | ] = a_list[ +123 | | 1 +124 | | ] + 2 + 3 + | |_________^ +125 | +126 | # Parentheses around the target don't reach the AST, so the comparison against the assignment + | +help: Replace with augmented assignment + | +121 | 1 + - ] = a_list[ + - 1 + - ] + 2 + 3 +122 + ] += 2 + 3 +123 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:128:1 + | +126 | # Parentheses around the target don't reach the AST, so the comparison against the assignment +127 | # target still matches. +128 | index = (index) + 1 + 2 + | ^^^^^^^^^^^^^^^^^^^^^^^ +129 | +130 | # In a chain, the operands that stay on the right-hand side keep their order, so a side effect in + | +help: Replace with augmented assignment + | +127 | # target still matches. + - index = (index) + 1 + 2 +128 + index += 1 + 2 +129 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `*=` to perform an augmented assignment directly + --> non_augmented_assignment.py:132:1 + | +130 | # In a chain, the operands that stay on the right-hand side keep their order, so a side effect in +131 | # one of them still runs exactly once, at the same point in the evaluation. +132 | to_multiply = to_multiply * (a_number := 2) * 3 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +133 | +134 | # Floating-point addition is not associative, so this fix can change the last bits of the result. + | +help: Replace with augmented assignment + | +131 | # one of them still runs exactly once, at the same point in the evaluation. + - to_multiply = to_multiply * (a_number := 2) * 3 +132 + to_multiply *= (a_number := 2) * 3 +133 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:136:1 + | +134 | # Floating-point addition is not associative, so this fix can change the last bits of the result. +135 | # It is reported anyway, in line with the rest of the rule's unsafe fixes. +136 | a_float = a_float + 0.1 + 0.2 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +137 | +138 | # `**` is right-associative, so `to_cube**2**3` is `to_cube ** (2**3)`: not a chain at all, but a + | +help: Replace with augmented assignment + | +135 | # It is reported anyway, in line with the rest of the rule's unsafe fixes. + - a_float = a_float + 0.1 + 0.2 +136 + a_float += 0.1 + 0.2 +137 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `**=` to perform an augmented assignment directly + --> non_augmented_assignment.py:140:1 + | +138 | # `**` is right-associative, so `to_cube**2**3` is `to_cube ** (2**3)`: not a chain at all, but a +139 | # single operation whose left operand happens to be the target. +140 | to_cube = to_cube**2**3 + | ^^^^^^^^^^^^^^^^^^^^^^^ +141 | +142 | # The parentheses that keep these continuation lines legal are dropped along with the rest of the + | +help: Replace with augmented assignment + | +139 | # single operation whose left operand happens to be the target. + - to_cube = to_cube**2**3 +140 + to_cube **= 2**3 +141 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:144:1 + | +142 | # The parentheses that keep these continuation lines legal are dropped along with the rest of the +143 | # statement, so the fix has to add its own. +144 | / index = ( +145 | | index +146 | | + 1 +147 | | + 2 +148 | | ) + | |_^ +149 | index = ( +150 | index + | +help: Replace with augmented assignment + | +143 | # statement, so the fix has to add its own. + - index = ( + - index + - + 1 + - + 2 + - ) +144 + index += (1 +145 + + 2) +146 | index = ( + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:149:1 + | +147 | + 2 +148 | ) +149 | / index = ( +150 | | index +151 | | + 1 # a comment inside the chain +152 | | + 2 +153 | | ) + | |_^ +154 | to_multiply = ( +155 | to_multiply + | +help: Replace with augmented assignment + | +148 | ) + - index = ( + - index + - + 1 # a comment inside the chain + - + 2 + - ) +149 + index += (1 # a comment inside the chain +150 + + 2) +151 | to_multiply = ( + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `*=` to perform an augmented assignment directly + --> non_augmented_assignment.py:154:1 + | +152 | + 2 +153 | ) +154 | / to_multiply = ( +155 | | to_multiply +156 | | * 2 +157 | | * (a_number + 1) +158 | | ) + | |_^ +159 | index = ( +160 | 1 + | +help: Replace with augmented assignment + | +153 | ) + - to_multiply = ( + - to_multiply + - * 2 + - * (a_number + 1) + - ) +154 + to_multiply *= (2 +155 + * (a_number + 1)) +156 | index = ( + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:159:1 + | +157 | * (a_number + 1) +158 | ) +159 | / index = ( +160 | | 1 +161 | | + 2 +162 | | + index +163 | | ) + | |_^ +164 | some_string = ( +165 | some_string + | +help: Replace with augmented assignment + | +158 | ) + - index = ( + - 1 + - + 2 + - + index + - ) +159 + index += (1 +160 + + 2) +161 | some_string = ( + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:164:1 + | +162 | + index +163 | ) +164 | / some_string = ( +165 | | some_string +166 | | + "implicitly" +167 | | "concatenated" +168 | | ) + | |_^ +169 | +170 | # Chains where the target is the rightmost operand, and every other operand is a number. + | +help: Replace with augmented assignment + | +163 | ) + - some_string = ( + - some_string + - + "implicitly" + - "concatenated" + - ) +164 + some_string += ("implicitly" +165 + "concatenated") +166 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `*=` to perform an augmented assignment directly + --> non_augmented_assignment.py:171:1 + | +170 | # Chains where the target is the rightmost operand, and every other operand is a number. +171 | to_multiply = 2 * 3 * to_multiply + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +172 | index = 1 + 2 + index +173 | index = 1 + 2 * 3 + index + | +help: Replace with augmented assignment + | +170 | # Chains where the target is the rightmost operand, and every other operand is a number. + - to_multiply = 2 * 3 * to_multiply +171 + to_multiply *= 2 * 3 +172 | index = 1 + 2 + index + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:172:1 + | +170 | # Chains where the target is the rightmost operand, and every other operand is a number. +171 | to_multiply = 2 * 3 * to_multiply +172 | index = 1 + 2 + index + | ^^^^^^^^^^^^^^^^^^^^^ +173 | index = 1 + 2 * 3 + index +174 | to_multiply = 2 * 3 * 4 * to_multiply + | +help: Replace with augmented assignment + | +171 | to_multiply = 2 * 3 * to_multiply + - index = 1 + 2 + index +172 + index += 1 + 2 +173 | index = 1 + 2 * 3 + index + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:173:1 + | +171 | to_multiply = 2 * 3 * to_multiply +172 | index = 1 + 2 + index +173 | index = 1 + 2 * 3 + index + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +174 | to_multiply = 2 * 3 * 4 * to_multiply +175 | flags = 0x1 | 0x2 | flags + | +help: Replace with augmented assignment + | +172 | index = 1 + 2 + index + - index = 1 + 2 * 3 + index +173 + index += 1 + 2 * 3 +174 | to_multiply = 2 * 3 * 4 * to_multiply + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `*=` to perform an augmented assignment directly + --> non_augmented_assignment.py:174:1 + | +172 | index = 1 + 2 + index +173 | index = 1 + 2 * 3 + index +174 | to_multiply = 2 * 3 * 4 * to_multiply + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +175 | flags = 0x1 | 0x2 | flags + | +help: Replace with augmented assignment + | +173 | index = 1 + 2 * 3 + index + - to_multiply = 2 * 3 * 4 * to_multiply +174 + to_multiply *= 2 * 3 * 4 +175 | flags = 0x1 | 0x2 | flags + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `|=` to perform an augmented assignment directly + --> non_augmented_assignment.py:175:1 + | +173 | index = 1 + 2 * 3 + index +174 | to_multiply = 2 * 3 * 4 * to_multiply +175 | flags = 0x1 | 0x2 | flags + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +176 | +177 | # Unary `+`, `-` and `~` applied to a number still give a number. + | +help: Replace with augmented assignment + | +174 | to_multiply = 2 * 3 * 4 * to_multiply + - flags = 0x1 | 0x2 | flags +175 + flags |= 0x1 | 0x2 +176 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:178:1 + | +177 | # Unary `+`, `-` and `~` applied to a number still give a number. +178 | index = -1 + index + | ^^^^^^^^^^^^^^^^^^ +179 | index = -1 + -2 + index +180 | to_multiply = +2 * -3 * to_multiply + | +help: Replace with augmented assignment + | +177 | # Unary `+`, `-` and `~` applied to a number still give a number. + - index = -1 + index +178 + index += -1 +179 | index = -1 + -2 + index + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:179:1 + | +177 | # Unary `+`, `-` and `~` applied to a number still give a number. +178 | index = -1 + index +179 | index = -1 + -2 + index + | ^^^^^^^^^^^^^^^^^^^^^^^ +180 | to_multiply = +2 * -3 * to_multiply +181 | flags = ~0x1 | 0x2 | flags + | +help: Replace with augmented assignment + | +178 | index = -1 + index + - index = -1 + -2 + index +179 + index += -1 + -2 +180 | to_multiply = +2 * -3 * to_multiply + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `*=` to perform an augmented assignment directly + --> non_augmented_assignment.py:180:1 + | +178 | index = -1 + index +179 | index = -1 + -2 + index +180 | to_multiply = +2 * -3 * to_multiply + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +181 | flags = ~0x1 | 0x2 | flags + | +help: Replace with augmented assignment + | +179 | index = -1 + -2 + index + - to_multiply = +2 * -3 * to_multiply +180 + to_multiply *= +2 * -3 +181 | flags = ~0x1 | 0x2 | flags + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `|=` to perform an augmented assignment directly + --> non_augmented_assignment.py:181:1 + | +179 | index = -1 + -2 + index +180 | to_multiply = +2 * -3 * to_multiply +181 | flags = ~0x1 | 0x2 | flags + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: Replace with augmented assignment + | +180 | to_multiply = +2 * -3 * to_multiply + - flags = ~0x1 | 0x2 | flags +181 + flags |= ~0x1 | 0x2 +182 | + | +note: This is an unsafe fix and may change runtime behavior + +PLR6104 [*] Use `+=` to perform an augmented assignment directly + --> non_augmented_assignment.py:186:9 + | +184 | class U: +185 | def u(self): +186 | self.a = self.a + 1 + 2 + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: Replace with augmented assignment + | +185 | def u(self): + - self.a = self.a + 1 + 2 +186 + self.a += 1 + 2 +187 | + | +note: This is an unsafe fix and may change runtime behavior From fdf86709bac3a1cb19ecc07db73e73f8b7f24d9e Mon Sep 17 00:00:00 2001 From: Avasam Date: Tue, 28 Jul 2026 12:29:31 -0400 Subject: [PATCH 2/2] Extract comment to another PR --- .../src/rules/pylint/rules/non_augmented_assignment.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/ruff_linter/src/rules/pylint/rules/non_augmented_assignment.rs b/crates/ruff_linter/src/rules/pylint/rules/non_augmented_assignment.rs index c296f71e6c0921..4b432ebfa5717d 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/non_augmented_assignment.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/non_augmented_assignment.rs @@ -81,13 +81,6 @@ use crate::{AlwaysFixableViolation, Edit, Fix}; /// assert (foo, bar) == ([1, 2], [1, 2]) /// ``` /// -/// An augmented assignment can also fail where the plain form succeeds. NumPy -/// writes the result into the target's buffer, so `a *= b` raises where -/// `a = a * b` would broadcast to a new shape or promote the dtype. The same -/// applies to `a @= b`, which requires the product to have the target's shape. -/// -/// The fix replaces the whole statement, so any comments inside it are lost. -/// /// It also regroups the operands of a chain, e.g., `x = x + y + z` becomes /// `x += y + z`. Floating-point addition and multiplication are not /// associative, so the result can differ in the last bits: `(0.1 + 0.2) + 0.3`