From 6050bab5db4ca3e903db79dd185e1eec468ea018 Mon Sep 17 00:00:00 2001 From: Aleksei Latyshev Date: Sun, 7 Apr 2024 04:31:59 +0200 Subject: [PATCH] [`refurb`] Support `itemgetter` in `reimplemented-operator` (`FURB118`) (#10526) ## Summary Lint about function like expressions which are equivalent to `operator.itemgetter`. See: https://github.com/astral-sh/ruff/issues/1348#issuecomment-1909421747 ## Test Plan cargo test --- .../resources/test/fixtures/refurb/FURB118.py | 19 +- .../refurb/rules/reimplemented_operator.rs | 215 +++++++++++------- ...es__refurb__tests__FURB118_FURB118.py.snap | 170 +++++++++++--- 3 files changed, 289 insertions(+), 115 deletions(-) diff --git a/crates/ruff_linter/resources/test/fixtures/refurb/FURB118.py b/crates/ruff_linter/resources/test/fixtures/refurb/FURB118.py index 51c136f976558..6e8c3d7676091 100644 --- a/crates/ruff_linter/resources/test/fixtures/refurb/FURB118.py +++ b/crates/ruff_linter/resources/test/fixtures/refurb/FURB118.py @@ -10,7 +10,7 @@ op_matmutl = lambda x, y: x @ y op_truediv = lambda x, y: x / y op_mod = lambda x, y: x % y -op_pow = lambda x, y: x ** y +op_pow = lambda x, y: x**y op_lshift = lambda x, y: x << y op_rshift = lambda x, y: x >> y op_bitor = lambda x, y: x | y @@ -27,6 +27,10 @@ op_is = lambda x, y: x is y op_isnot = lambda x, y: x is not y op_in = lambda x, y: y in x +op_itemgetter = lambda x: x[0] +op_itemgetter = lambda x: (x[0], x[1], x[2]) +op_itemgetter = lambda x: (x[1:], x[2]) +op_itemgetter = lambda x: x[:] def op_not2(x): @@ -41,21 +45,30 @@ class Adder: def add(x, y): return x + y + # OK. -op_add3 = lambda x, y = 1: x + y +op_add3 = lambda x, y=1: x + y op_neg2 = lambda x, y: y - x op_notin = lambda x, y: y not in x op_and = lambda x, y: y and x op_or = lambda x, y: y or x op_in = lambda x, y: x in y +op_itemgetter = lambda x: (1, x[1], x[2]) +op_itemgetter = lambda x: (x.y, x[1], x[2]) +op_itemgetter = lambda x, y: (x[0], y[0]) +op_itemgetter = lambda x, y: (x[0], y[0]) +op_itemgetter = lambda x: () +op_itemgetter = lambda x: (*x[0], x[1]) def op_neg3(x, y): return y - x -def op_add4(x, y = 1): + +def op_add4(x, y=1): return x + y + def op_add5(x, y): print("op_add5") return x + y diff --git a/crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs b/crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs index 7f5f0ea75973f..c13a385563ef5 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs @@ -1,9 +1,13 @@ +use std::borrow::Cow; +use std::fmt::{Debug, Display, Formatter}; + use anyhow::Result; use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation}; use ruff_macros::{derive_message_formats, violation}; -use ruff_python_ast::{self as ast, Expr, Stmt}; +use ruff_python_ast::{self as ast, Expr, ExprSlice, ExprSubscript, ExprTuple, Parameters, Stmt}; use ruff_python_semantic::SemanticModel; +use ruff_source_file::Locator; use ruff_text_size::{Ranged, TextRange}; use crate::checkers::ast::Checker; @@ -39,7 +43,7 @@ use crate::importer::{ImportRequest, Importer}; /// ## References #[violation] pub struct ReimplementedOperator { - operator: &'static str, + operator: Operator, target: FunctionLikeKind, } @@ -71,9 +75,10 @@ pub(crate) fn reimplemented_operator(checker: &mut Checker, target: &FunctionLik return; }; let Some(body) = target.body() else { return }; - let Some(operator) = get_operator(body, params) else { + let Some(operator) = get_operator(body, params, checker.locator()) else { return; }; + let fix = target.try_fix(&operator, checker.importer(), checker.semantic()); let mut diagnostic = Diagnostic::new( ReimplementedOperator { operator, @@ -81,8 +86,7 @@ pub(crate) fn reimplemented_operator(checker: &mut Checker, target: &FunctionLik }, target.range(), ); - diagnostic - .try_set_optional_fix(|| target.try_fix(operator, checker.importer(), checker.semantic())); + diagnostic.try_set_optional_fix(|| fix); checker.diagnostics.push(diagnostic); } @@ -115,8 +119,8 @@ impl Ranged for FunctionLike<'_> { } impl FunctionLike<'_> { - /// Return the [`ast::Parameters`] of the function-like node. - fn parameters(&self) -> Option<&ast::Parameters> { + /// Return the [`Parameters`] of the function-like node. + fn parameters(&self) -> Option<&Parameters> { match self { Self::Lambda(expr) => expr.parameters.as_deref(), Self::Function(stmt) => Some(&stmt.parameters), @@ -149,19 +153,24 @@ impl FunctionLike<'_> { /// function from `operator` module. fn try_fix( &self, - operator: &'static str, + operator: &Operator, importer: &Importer, semantic: &SemanticModel, ) -> Result> { match self { Self::Lambda(_) => { let (edit, binding) = importer.get_or_import_symbol( - &ImportRequest::import("operator", operator), + &ImportRequest::import("operator", operator.name), self.start(), semantic, )?; + let content = if operator.args.is_empty() { + binding + } else { + format!("{binding}({})", operator.args.join(", ")) + }; Ok(Some(Fix::safe_edits( - Edit::range_replacement(binding, self.range()), + Edit::range_replacement(content, self.range()), [edit], ))) } @@ -170,12 +179,112 @@ impl FunctionLike<'_> { } } -/// Return the name of the `operator` implemented by the given expression. -fn get_operator(expr: &Expr, params: &ast::Parameters) -> Option<&'static str> { +/// Convert the slice expression to the string representation of `slice` call. +/// For example, expression `1:2` will be `slice(1, 2)`, and `:` will be `slice(None)`. +fn slice_expr_to_slice_call(slice: &ExprSlice, locator: &Locator) -> String { + let stringify = |expr: Option<&Expr>| expr.map_or("None", |expr| locator.slice(expr)); + match ( + slice.lower.as_deref(), + slice.upper.as_deref(), + slice.step.as_deref(), + ) { + (lower, upper, step @ Some(_)) => format!( + "slice({}, {}, {})", + stringify(lower), + stringify(upper), + stringify(step) + ), + (None, upper, None) => format!("slice({})", stringify(upper)), + (lower @ Some(_), upper, None) => { + format!("slice({}, {})", stringify(lower), stringify(upper)) + } + } +} + +/// Convert the given expression to a string representation, suitable to be a function argument. +fn subscript_slice_to_string<'a>(expr: &Expr, locator: &Locator<'a>) -> Cow<'a, str> { + if let Expr::Slice(expr_slice) = expr { + Cow::Owned(slice_expr_to_slice_call(expr_slice, locator)) + } else { + Cow::Borrowed(locator.slice(expr)) + } +} + +/// Return the `operator` implemented by given subscript expression. +fn itemgetter_op(expr: &ExprSubscript, params: &Parameters, locator: &Locator) -> Option { + let [arg] = params.args.as_slice() else { + return None; + }; + if !is_same_expression(arg, &expr.value) { + return None; + }; + Some(Operator { + name: "itemgetter", + args: vec![subscript_slice_to_string(expr.slice.as_ref(), locator).to_string()], + }) +} + +/// Return the `operator` implemented by given tuple expression. +fn itemgetter_op_tuple( + expr: &ExprTuple, + params: &Parameters, + locator: &Locator, +) -> Option { + let [arg] = params.args.as_slice() else { + return None; + }; + if expr.elts.is_empty() { + return None; + } + Some(Operator { + name: "itemgetter", + args: expr + .elts + .iter() + .map(|expr| { + expr.as_subscript_expr() + .filter(|expr| is_same_expression(arg, &expr.value)) + .map(|expr| expr.slice.as_ref()) + .map(|slice| subscript_slice_to_string(slice, locator).to_string()) + }) + .collect::>>()?, + }) +} + +#[derive(Eq, PartialEq, Debug)] +struct Operator { + name: &'static str, + args: Vec, +} + +impl From<&'static str> for Operator { + fn from(value: &'static str) -> Self { + Self { + name: value, + args: vec![], + } + } +} + +impl Display for Operator { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name)?; + if self.args.is_empty() { + Ok(()) + } else { + write!(f, "({})", self.args.join(", ")) + } + } +} + +/// Return the `operator` implemented by the given expression. +fn get_operator(expr: &Expr, params: &Parameters, locator: &Locator) -> Option { match expr { - Expr::UnaryOp(expr) => unary_op(expr, params), - Expr::BinOp(expr) => bin_op(expr, params), - Expr::Compare(expr) => cmp_op(expr, params), + Expr::UnaryOp(expr) => unary_op(expr, params).map(Operator::from), + Expr::BinOp(expr) => bin_op(expr, params).map(Operator::from), + Expr::Compare(expr) => cmp_op(expr, params).map(Operator::from), + Expr::Subscript(expr) => itemgetter_op(expr, params, locator), + Expr::Tuple(expr) => itemgetter_op_tuple(expr, params, locator), _ => None, } } @@ -187,7 +296,7 @@ enum FunctionLikeKind { } /// Return the name of the `operator` implemented by the given unary expression. -fn unary_op(expr: &ast::ExprUnaryOp, params: &ast::Parameters) -> Option<&'static str> { +fn unary_op(expr: &ast::ExprUnaryOp, params: &Parameters) -> Option<&'static str> { let [arg] = params.args.as_slice() else { return None; }; @@ -203,7 +312,7 @@ fn unary_op(expr: &ast::ExprUnaryOp, params: &ast::Parameters) -> Option<&'stati } /// Return the name of the `operator` implemented by the given binary expression. -fn bin_op(expr: &ast::ExprBinOp, params: &ast::Parameters) -> Option<&'static str> { +fn bin_op(expr: &ast::ExprBinOp, params: &Parameters) -> Option<&'static str> { let [arg1, arg2] = params.args.as_slice() else { return None; }; @@ -228,7 +337,7 @@ fn bin_op(expr: &ast::ExprBinOp, params: &ast::Parameters) -> Option<&'static st } /// Return the name of the `operator` implemented by the given comparison expression. -fn cmp_op(expr: &ast::ExprCompare, params: &ast::Parameters) -> Option<&'static str> { +fn cmp_op(expr: &ast::ExprCompare, params: &Parameters) -> Option<&'static str> { let [arg1, arg2] = params.args.as_slice() else { return None; }; @@ -240,71 +349,19 @@ fn cmp_op(expr: &ast::ExprCompare, params: &ast::Parameters) -> Option<&'static }; match op { - ast::CmpOp::Eq => { - if match_arguments(arg1, arg2, &expr.left, right) { - Some("eq") - } else { - None - } - } - ast::CmpOp::NotEq => { - if match_arguments(arg1, arg2, &expr.left, right) { - Some("ne") - } else { - None - } - } - ast::CmpOp::Lt => { - if match_arguments(arg1, arg2, &expr.left, right) { - Some("lt") - } else { - None - } - } - ast::CmpOp::LtE => { - if match_arguments(arg1, arg2, &expr.left, right) { - Some("le") - } else { - None - } - } - ast::CmpOp::Gt => { - if match_arguments(arg1, arg2, &expr.left, right) { - Some("gt") - } else { - None - } - } - ast::CmpOp::GtE => { - if match_arguments(arg1, arg2, &expr.left, right) { - Some("ge") - } else { - None - } - } - ast::CmpOp::Is => { - if match_arguments(arg1, arg2, &expr.left, right) { - Some("is_") - } else { - None - } - } - ast::CmpOp::IsNot => { - if match_arguments(arg1, arg2, &expr.left, right) { - Some("is_not") - } else { - None - } - } + ast::CmpOp::Eq => match_arguments(arg1, arg2, &expr.left, right).then_some("eq"), + ast::CmpOp::NotEq => match_arguments(arg1, arg2, &expr.left, right).then_some("ne"), + ast::CmpOp::Lt => match_arguments(arg1, arg2, &expr.left, right).then_some("lt"), + ast::CmpOp::LtE => match_arguments(arg1, arg2, &expr.left, right).then_some("le"), + ast::CmpOp::Gt => match_arguments(arg1, arg2, &expr.left, right).then_some("gt"), + ast::CmpOp::GtE => match_arguments(arg1, arg2, &expr.left, right).then_some("ge"), + ast::CmpOp::Is => match_arguments(arg1, arg2, &expr.left, right).then_some("is_"), + ast::CmpOp::IsNot => match_arguments(arg1, arg2, &expr.left, right).then_some("is_not"), ast::CmpOp::In => { // Note: `operator.contains` reverses the order of arguments. That is: // `operator.contains` is equivalent to `lambda x, y: y in x`, rather than // `lambda x, y: x in y`. - if match_arguments(arg1, arg2, right, &expr.left) { - Some("contains") - } else { - None - } + match_arguments(arg1, arg2, right, &expr.left).then_some("contains") } ast::CmpOp::NotIn => None, } diff --git a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB118_FURB118.py.snap b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB118_FURB118.py.snap index 828a95ee3b5ea..6c208bcd9530d 100644 --- a/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB118_FURB118.py.snap +++ b/crates/ruff_linter/src/rules/refurb/snapshots/ruff_linter__rules__refurb__tests__FURB118_FURB118.py.snap @@ -187,7 +187,7 @@ FURB118.py:10:14: FURB118 [*] Use `operator.matmul` instead of defining a lambda 11 |+op_matmutl = operator.matmul 11 12 | op_truediv = lambda x, y: x / y 12 13 | op_mod = lambda x, y: x % y -13 14 | op_pow = lambda x, y: x ** y +13 14 | op_pow = lambda x, y: x**y FURB118.py:11:14: FURB118 [*] Use `operator.truediv` instead of defining a lambda | @@ -196,7 +196,7 @@ FURB118.py:11:14: FURB118 [*] Use `operator.truediv` instead of defining a lambd 11 | op_truediv = lambda x, y: x / y | ^^^^^^^^^^^^^^^^^^ FURB118 12 | op_mod = lambda x, y: x % y -13 | op_pow = lambda x, y: x ** y +13 | op_pow = lambda x, y: x**y | = help: Replace with `operator.truediv` @@ -213,7 +213,7 @@ FURB118.py:11:14: FURB118 [*] Use `operator.truediv` instead of defining a lambd 11 |-op_truediv = lambda x, y: x / y 12 |+op_truediv = operator.truediv 12 13 | op_mod = lambda x, y: x % y -13 14 | op_pow = lambda x, y: x ** y +13 14 | op_pow = lambda x, y: x**y 14 15 | op_lshift = lambda x, y: x << y FURB118.py:12:10: FURB118 [*] Use `operator.mod` instead of defining a lambda @@ -222,7 +222,7 @@ FURB118.py:12:10: FURB118 [*] Use `operator.mod` instead of defining a lambda 11 | op_truediv = lambda x, y: x / y 12 | op_mod = lambda x, y: x % y | ^^^^^^^^^^^^^^^^^^ FURB118 -13 | op_pow = lambda x, y: x ** y +13 | op_pow = lambda x, y: x**y 14 | op_lshift = lambda x, y: x << y | = help: Replace with `operator.mod` @@ -239,7 +239,7 @@ FURB118.py:12:10: FURB118 [*] Use `operator.mod` instead of defining a lambda 11 12 | op_truediv = lambda x, y: x / y 12 |-op_mod = lambda x, y: x % y 13 |+op_mod = operator.mod -13 14 | op_pow = lambda x, y: x ** y +13 14 | op_pow = lambda x, y: x**y 14 15 | op_lshift = lambda x, y: x << y 15 16 | op_rshift = lambda x, y: x >> y @@ -247,8 +247,8 @@ FURB118.py:13:10: FURB118 [*] Use `operator.pow` instead of defining a lambda | 11 | op_truediv = lambda x, y: x / y 12 | op_mod = lambda x, y: x % y -13 | op_pow = lambda x, y: x ** y - | ^^^^^^^^^^^^^^^^^^^ FURB118 +13 | op_pow = lambda x, y: x**y + | ^^^^^^^^^^^^^^^^^ FURB118 14 | op_lshift = lambda x, y: x << y 15 | op_rshift = lambda x, y: x >> y | @@ -264,7 +264,7 @@ FURB118.py:13:10: FURB118 [*] Use `operator.pow` instead of defining a lambda 10 11 | op_matmutl = lambda x, y: x @ y 11 12 | op_truediv = lambda x, y: x / y 12 13 | op_mod = lambda x, y: x % y -13 |-op_pow = lambda x, y: x ** y +13 |-op_pow = lambda x, y: x**y 14 |+op_pow = operator.pow 14 15 | op_lshift = lambda x, y: x << y 15 16 | op_rshift = lambda x, y: x >> y @@ -273,7 +273,7 @@ FURB118.py:13:10: FURB118 [*] Use `operator.pow` instead of defining a lambda FURB118.py:14:13: FURB118 [*] Use `operator.lshift` instead of defining a lambda | 12 | op_mod = lambda x, y: x % y -13 | op_pow = lambda x, y: x ** y +13 | op_pow = lambda x, y: x**y 14 | op_lshift = lambda x, y: x << y | ^^^^^^^^^^^^^^^^^^^ FURB118 15 | op_rshift = lambda x, y: x >> y @@ -290,7 +290,7 @@ FURB118.py:14:13: FURB118 [*] Use `operator.lshift` instead of defining a lambda -------------------------------------------------------------------------------- 11 12 | op_truediv = lambda x, y: x / y 12 13 | op_mod = lambda x, y: x % y -13 14 | op_pow = lambda x, y: x ** y +13 14 | op_pow = lambda x, y: x**y 14 |-op_lshift = lambda x, y: x << y 15 |+op_lshift = operator.lshift 15 16 | op_rshift = lambda x, y: x >> y @@ -299,7 +299,7 @@ FURB118.py:14:13: FURB118 [*] Use `operator.lshift` instead of defining a lambda FURB118.py:15:13: FURB118 [*] Use `operator.rshift` instead of defining a lambda | -13 | op_pow = lambda x, y: x ** y +13 | op_pow = lambda x, y: x**y 14 | op_lshift = lambda x, y: x << y 15 | op_rshift = lambda x, y: x >> y | ^^^^^^^^^^^^^^^^^^^ FURB118 @@ -316,7 +316,7 @@ FURB118.py:15:13: FURB118 [*] Use `operator.rshift` instead of defining a lambda 4 5 | op_pos = lambda x: +x -------------------------------------------------------------------------------- 12 13 | op_mod = lambda x, y: x % y -13 14 | op_pow = lambda x, y: x ** y +13 14 | op_pow = lambda x, y: x**y 14 15 | op_lshift = lambda x, y: x << y 15 |-op_rshift = lambda x, y: x >> y 16 |+op_rshift = operator.rshift @@ -342,7 +342,7 @@ FURB118.py:16:12: FURB118 [*] Use `operator.or_` instead of defining a lambda 3 4 | op_not = lambda x: not x 4 5 | op_pos = lambda x: +x -------------------------------------------------------------------------------- -13 14 | op_pow = lambda x, y: x ** y +13 14 | op_pow = lambda x, y: x**y 14 15 | op_lshift = lambda x, y: x << y 15 16 | op_rshift = lambda x, y: x >> y 16 |-op_bitor = lambda x, y: x | y @@ -617,7 +617,7 @@ FURB118.py:27:9: FURB118 [*] Use `operator.is_` instead of defining a lambda 28 |+op_is = operator.is_ 28 29 | op_isnot = lambda x, y: x is not y 29 30 | op_in = lambda x, y: y in x -30 31 | +30 31 | op_itemgetter = lambda x: x[0] FURB118.py:28:12: FURB118 [*] Use `operator.is_not` instead of defining a lambda | @@ -626,6 +626,7 @@ FURB118.py:28:12: FURB118 [*] Use `operator.is_not` instead of defining a lambda 28 | op_isnot = lambda x, y: x is not y | ^^^^^^^^^^^^^^^^^^^^^^^ FURB118 29 | op_in = lambda x, y: y in x +30 | op_itemgetter = lambda x: x[0] | = help: Replace with `operator.is_not` @@ -642,8 +643,8 @@ FURB118.py:28:12: FURB118 [*] Use `operator.is_not` instead of defining a lambda 28 |-op_isnot = lambda x, y: x is not y 29 |+op_isnot = operator.is_not 29 30 | op_in = lambda x, y: y in x -30 31 | -31 32 | +30 31 | op_itemgetter = lambda x: x[0] +31 32 | op_itemgetter = lambda x: (x[0], x[1], x[2]) FURB118.py:29:9: FURB118 [*] Use `operator.contains` instead of defining a lambda | @@ -651,6 +652,8 @@ FURB118.py:29:9: FURB118 [*] Use `operator.contains` instead of defining a lambd 28 | op_isnot = lambda x, y: x is not y 29 | op_in = lambda x, y: y in x | ^^^^^^^^^^^^^^^^^^^ FURB118 +30 | op_itemgetter = lambda x: x[0] +31 | op_itemgetter = lambda x: (x[0], x[1], x[2]) | = help: Replace with `operator.contains` @@ -666,36 +669,137 @@ FURB118.py:29:9: FURB118 [*] Use `operator.contains` instead of defining a lambd 28 29 | op_isnot = lambda x, y: x is not y 29 |-op_in = lambda x, y: y in x 30 |+op_in = operator.contains -30 31 | -31 32 | -32 33 | def op_not2(x): +30 31 | op_itemgetter = lambda x: x[0] +31 32 | op_itemgetter = lambda x: (x[0], x[1], x[2]) +32 33 | op_itemgetter = lambda x: (x[1:], x[2]) + +FURB118.py:30:17: FURB118 [*] Use `operator.itemgetter(0)` instead of defining a lambda + | +28 | op_isnot = lambda x, y: x is not y +29 | op_in = lambda x, y: y in x +30 | op_itemgetter = lambda x: x[0] + | ^^^^^^^^^^^^^^ FURB118 +31 | op_itemgetter = lambda x: (x[0], x[1], x[2]) +32 | op_itemgetter = lambda x: (x[1:], x[2]) + | + = help: Replace with `operator.itemgetter(0)` + +ℹ Safe fix +1 1 | # Errors. + 2 |+import operator +2 3 | op_bitnot = lambda x: ~x +3 4 | op_not = lambda x: not x +4 5 | op_pos = lambda x: +x +-------------------------------------------------------------------------------- +27 28 | op_is = lambda x, y: x is y +28 29 | op_isnot = lambda x, y: x is not y +29 30 | op_in = lambda x, y: y in x +30 |-op_itemgetter = lambda x: x[0] + 31 |+op_itemgetter = operator.itemgetter(0) +31 32 | op_itemgetter = lambda x: (x[0], x[1], x[2]) +32 33 | op_itemgetter = lambda x: (x[1:], x[2]) +33 34 | op_itemgetter = lambda x: x[:] + +FURB118.py:31:17: FURB118 [*] Use `operator.itemgetter(0, 1, 2)` instead of defining a lambda + | +29 | op_in = lambda x, y: y in x +30 | op_itemgetter = lambda x: x[0] +31 | op_itemgetter = lambda x: (x[0], x[1], x[2]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FURB118 +32 | op_itemgetter = lambda x: (x[1:], x[2]) +33 | op_itemgetter = lambda x: x[:] + | + = help: Replace with `operator.itemgetter(0, 1, 2)` + +ℹ Safe fix +1 1 | # Errors. + 2 |+import operator +2 3 | op_bitnot = lambda x: ~x +3 4 | op_not = lambda x: not x +4 5 | op_pos = lambda x: +x +-------------------------------------------------------------------------------- +28 29 | op_isnot = lambda x, y: x is not y +29 30 | op_in = lambda x, y: y in x +30 31 | op_itemgetter = lambda x: x[0] +31 |-op_itemgetter = lambda x: (x[0], x[1], x[2]) + 32 |+op_itemgetter = operator.itemgetter(0, 1, 2) +32 33 | op_itemgetter = lambda x: (x[1:], x[2]) +33 34 | op_itemgetter = lambda x: x[:] +34 35 | -FURB118.py:32:1: FURB118 Use `operator.not_` instead of defining a function +FURB118.py:32:17: FURB118 [*] Use `operator.itemgetter(slice(1, None), 2)` instead of defining a lambda | -32 | / def op_not2(x): -33 | | return not x +30 | op_itemgetter = lambda x: x[0] +31 | op_itemgetter = lambda x: (x[0], x[1], x[2]) +32 | op_itemgetter = lambda x: (x[1:], x[2]) + | ^^^^^^^^^^^^^^^^^^^^^^^ FURB118 +33 | op_itemgetter = lambda x: x[:] + | + = help: Replace with `operator.itemgetter(slice(1, None), 2)` + +ℹ Safe fix +1 1 | # Errors. + 2 |+import operator +2 3 | op_bitnot = lambda x: ~x +3 4 | op_not = lambda x: not x +4 5 | op_pos = lambda x: +x +-------------------------------------------------------------------------------- +29 30 | op_in = lambda x, y: y in x +30 31 | op_itemgetter = lambda x: x[0] +31 32 | op_itemgetter = lambda x: (x[0], x[1], x[2]) +32 |-op_itemgetter = lambda x: (x[1:], x[2]) + 33 |+op_itemgetter = operator.itemgetter(slice(1, None), 2) +33 34 | op_itemgetter = lambda x: x[:] +34 35 | +35 36 | + +FURB118.py:33:17: FURB118 [*] Use `operator.itemgetter(slice(None))` instead of defining a lambda + | +31 | op_itemgetter = lambda x: (x[0], x[1], x[2]) +32 | op_itemgetter = lambda x: (x[1:], x[2]) +33 | op_itemgetter = lambda x: x[:] + | ^^^^^^^^^^^^^^ FURB118 + | + = help: Replace with `operator.itemgetter(slice(None))` + +ℹ Safe fix +1 1 | # Errors. + 2 |+import operator +2 3 | op_bitnot = lambda x: ~x +3 4 | op_not = lambda x: not x +4 5 | op_pos = lambda x: +x +-------------------------------------------------------------------------------- +30 31 | op_itemgetter = lambda x: x[0] +31 32 | op_itemgetter = lambda x: (x[0], x[1], x[2]) +32 33 | op_itemgetter = lambda x: (x[1:], x[2]) +33 |-op_itemgetter = lambda x: x[:] + 34 |+op_itemgetter = operator.itemgetter(slice(None)) +34 35 | +35 36 | +36 37 | def op_not2(x): + +FURB118.py:36:1: FURB118 Use `operator.not_` instead of defining a function + | +36 | / def op_not2(x): +37 | | return not x | |________________^ FURB118 | = help: Replace with `operator.not_` -FURB118.py:36:1: FURB118 Use `operator.add` instead of defining a function +FURB118.py:40:1: FURB118 Use `operator.add` instead of defining a function | -36 | / def op_add2(x, y): -37 | | return x + y +40 | / def op_add2(x, y): +41 | | return x + y | |________________^ FURB118 | = help: Replace with `operator.add` -FURB118.py:41:5: FURB118 Use `operator.add` instead of defining a function +FURB118.py:45:5: FURB118 Use `operator.add` instead of defining a function | -40 | class Adder: -41 | def add(x, y): +44 | class Adder: +45 | def add(x, y): | _____^ -42 | | return x + y +46 | | return x + y | |____________________^ FURB118 -43 | -44 | # OK. | = help: Replace with `operator.add` - -