[`pylint`] Fix missing parens in unsafe fix for `unnecessary-dunder-call` (`PLC2801`) (#15762)

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
Mike Perlov 2025-02-04 04:54:01 -05:00 committed by GitHub
parent b848afeae8
commit 15dd3b5ebd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 798 additions and 364 deletions

View File

@ -48,6 +48,21 @@ x = -(-a).__add__(3) # PLC2801
# Calls
print(a.__call__()) # PLC2801 (no fix, intentional)
class Foo:
def __init__(self, v):
self.v = v
def __add__(self, other):
self.v += other
return self
def get_v(self):
return self.v
foo = Foo(1)
foo.__add__(2).get_v() # PLC2801
# Lambda expressions
blah = lambda: a.__add__(1) # PLC2801
@ -72,13 +87,22 @@ print(next(gen))
# Subscripts
print({"a": a.__add__(1)}["a"]) # PLC2801
# https://github.com/astral-sh/ruff/issues/15745
print("x".__add__("y")[0]) # PLC2801
# Starred
print(*[a.__add__(1)]) # PLC2801
list1 = [1, 2, 3]
list2 = [4, 5, 6]
print([*list1.__add__(list2)]) # PLC2801
# Slices
print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
# Attribute access
# https://github.com/astral-sh/ruff/issues/15745
print(1j.__add__(1.0).real) # PLC2801
class Thing:
def __init__(self, stuff: Any) -> None:

View File

@ -1,6 +1,6 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_python_ast::{self as ast, BoolOp, Expr, Operator, Stmt, UnaryOp};
use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged;
@ -107,7 +107,9 @@ pub(crate) fn unnecessary_dunder_call(checker: &mut Checker, call: &ast::ExprCal
return;
}
let mut fixed: Option<String> = None;
// If a fix is available, we'll store the text of the fixed expression here
// along with the precedence of the resulting expression.
let mut fixed: Option<(String, OperatorPrecedence)> = None;
let mut title: Option<String> = None;
if let Some(dunder) = DunderReplacement::from_method(attr) {
@ -116,37 +118,52 @@ pub(crate) fn unnecessary_dunder_call(checker: &mut Checker, call: &ast::ExprCal
if !checker.semantic().has_builtin_binding(replacement) {
return;
}
fixed = Some(format!(
"{}({})",
replacement,
checker.locator().slice(value.as_ref()),
fixed = Some((
format!(
"{}({})",
replacement,
checker.locator().slice(value.as_ref()),
),
OperatorPrecedence::CallAttribute,
));
title = Some(message.to_string());
}
([arg], DunderReplacement::Operator(replacement, message)) => {
([arg], DunderReplacement::Operator(replacement, message, precedence)) => {
let value_slice = checker.locator().slice(value.as_ref());
let arg_slice = checker.locator().slice(arg);
if can_be_represented_without_parentheses(arg) {
if OperatorPrecedence::from_expr(arg) > precedence {
// if it's something that can reasonably be removed from parentheses,
// we'll do that.
fixed = Some(format!("{value_slice} {replacement} {arg_slice}"));
fixed = Some((
format!("{value_slice} {replacement} {arg_slice}"),
precedence,
));
} else {
fixed = Some(format!("{value_slice} {replacement} ({arg_slice})"));
fixed = Some((
format!("{value_slice} {replacement} ({arg_slice})"),
precedence,
));
}
title = Some(message.to_string());
}
([arg], DunderReplacement::ROperator(replacement, message)) => {
([arg], DunderReplacement::ROperator(replacement, message, precedence)) => {
let value_slice = checker.locator().slice(value.as_ref());
let arg_slice = checker.locator().slice(arg);
if arg.is_attribute_expr() || arg.is_name_expr() || arg.is_literal_expr() {
if OperatorPrecedence::from_expr(arg) > precedence {
// if it's something that can reasonably be removed from parentheses,
// we'll do that.
fixed = Some(format!("{arg_slice} {replacement} {value_slice}"));
fixed = Some((
format!("{arg_slice} {replacement} {value_slice}"),
precedence,
));
} else {
fixed = Some(format!("({arg_slice}) {replacement} {value_slice}"));
fixed = Some((
format!("({arg_slice}) {replacement} {value_slice}"),
precedence,
));
}
title = Some(message.to_string());
}
@ -165,22 +182,23 @@ pub(crate) fn unnecessary_dunder_call(checker: &mut Checker, call: &ast::ExprCal
call.range(),
);
if let Some(mut fixed) = fixed {
if let Some((mut fixed, precedence)) = fixed {
let dunder = DunderReplacement::from_method(attr);
// We never need to wrap builtin functions in extra parens
// since function calls have high precedence
let wrap_in_paren = (!matches!(dunder, Some(DunderReplacement::Builtin(_,_))))
// By the looks of it, we don't need to wrap the expression in
// parens if it's the only argument to a call expression.
// Being in any other kind of expression though, we *will*
// add parens. e.g. `print(a.__add__(3))` -> `print(a + 3)`
// instead of `print((a + 3))`
// and `x = 2 * a.__add__(3)` -> `x = 2 * (a + 3)`
// If parent expression has higher precedence then the new replacement,
// it would associate with either the left operand (e.g. naive change from `a * b.__add__(c)`
// becomes `a * b + c` which is incorrect) or the right operand (e.g. naive change from
// `a.__add__(b).attr` becomes `a + b.attr` which is also incorrect).
// This rule doesn't apply to function calls despite them having higher
// precedence than any of our replacement, since they already wrap around
// our expression e.g. `print(a.__add__(3))` -> `print(a + 3)`
&& checker
.semantic()
.current_expression_parent()
.is_some_and(|parent| !can_be_represented_without_parentheses(parent));
.is_some_and(|parent| !parent.is_call_expr() && OperatorPrecedence::from_expr(parent) > precedence);
if wrap_in_paren {
fixed = format!("({fixed})");
@ -240,9 +258,9 @@ fn allowed_dunder_constants(dunder_method: &str, target_version: PythonVersion)
#[derive(Debug, Copy, Clone)]
enum DunderReplacement {
/// A dunder method that is an operator.
Operator(&'static str, &'static str),
Operator(&'static str, &'static str, OperatorPrecedence),
/// A dunder method that is a right-side operator.
ROperator(&'static str, &'static str),
ROperator(&'static str, &'static str, OperatorPrecedence),
/// A dunder method that is a builtin.
Builtin(&'static str, &'static str),
/// A dunder method that is a message only.
@ -252,48 +270,212 @@ enum DunderReplacement {
impl DunderReplacement {
fn from_method(dunder_method: &str) -> Option<Self> {
match dunder_method {
"__add__" => Some(Self::Operator("+", "Use `+` operator")),
"__and__" => Some(Self::Operator("&", "Use `&` operator")),
"__contains__" => Some(Self::ROperator("in", "Use `in` operator")),
"__eq__" => Some(Self::Operator("==", "Use `==` operator")),
"__floordiv__" => Some(Self::Operator("//", "Use `//` operator")),
"__ge__" => Some(Self::Operator(">=", "Use `>=` operator")),
"__gt__" => Some(Self::Operator(">", "Use `>` operator")),
"__iadd__" => Some(Self::Operator("+=", "Use `+=` operator")),
"__iand__" => Some(Self::Operator("&=", "Use `&=` operator")),
"__ifloordiv__" => Some(Self::Operator("//=", "Use `//=` operator")),
"__ilshift__" => Some(Self::Operator("<<=", "Use `<<=` operator")),
"__imod__" => Some(Self::Operator("%=", "Use `%=` operator")),
"__imul__" => Some(Self::Operator("*=", "Use `*=` operator")),
"__ior__" => Some(Self::Operator("|=", "Use `|=` operator")),
"__ipow__" => Some(Self::Operator("**=", "Use `**=` operator")),
"__irshift__" => Some(Self::Operator(">>=", "Use `>>=` operator")),
"__isub__" => Some(Self::Operator("-=", "Use `-=` operator")),
"__itruediv__" => Some(Self::Operator("/=", "Use `/=` operator")),
"__ixor__" => Some(Self::Operator("^=", "Use `^=` operator")),
"__le__" => Some(Self::Operator("<=", "Use `<=` operator")),
"__lshift__" => Some(Self::Operator("<<", "Use `<<` operator")),
"__lt__" => Some(Self::Operator("<", "Use `<` operator")),
"__mod__" => Some(Self::Operator("%", "Use `%` operator")),
"__mul__" => Some(Self::Operator("*", "Use `*` operator")),
"__ne__" => Some(Self::Operator("!=", "Use `!=` operator")),
"__or__" => Some(Self::Operator("|", "Use `|` operator")),
"__rshift__" => Some(Self::Operator(">>", "Use `>>` operator")),
"__sub__" => Some(Self::Operator("-", "Use `-` operator")),
"__truediv__" => Some(Self::Operator("/", "Use `/` operator")),
"__xor__" => Some(Self::Operator("^", "Use `^` operator")),
"__add__" => Some(Self::Operator(
"+",
"Use `+` operator",
OperatorPrecedence::AddSub,
)),
"__and__" => Some(Self::Operator(
"&",
"Use `&` operator",
OperatorPrecedence::BitAnd,
)),
"__contains__" => Some(Self::ROperator(
"in",
"Use `in` operator",
OperatorPrecedence::ComparisonsMembershipIdentity,
)),
"__eq__" => Some(Self::Operator(
"==",
"Use `==` operator",
OperatorPrecedence::ComparisonsMembershipIdentity,
)),
"__floordiv__" => Some(Self::Operator(
"//",
"Use `//` operator",
OperatorPrecedence::MulDivRemain,
)),
"__ge__" => Some(Self::Operator(
">=",
"Use `>=` operator",
OperatorPrecedence::ComparisonsMembershipIdentity,
)),
"__gt__" => Some(Self::Operator(
">",
"Use `>` operator",
OperatorPrecedence::ComparisonsMembershipIdentity,
)),
"__iadd__" => Some(Self::Operator(
"+=",
"Use `+=` operator",
OperatorPrecedence::Assign,
)),
"__iand__" => Some(Self::Operator(
"&=",
"Use `&=` operator",
OperatorPrecedence::Assign,
)),
"__ifloordiv__" => Some(Self::Operator(
"//=",
"Use `//=` operator",
OperatorPrecedence::Assign,
)),
"__ilshift__" => Some(Self::Operator(
"<<=",
"Use `<<=` operator",
OperatorPrecedence::Assign,
)),
"__imod__" => Some(Self::Operator(
"%=",
"Use `%=` operator",
OperatorPrecedence::Assign,
)),
"__imul__" => Some(Self::Operator(
"*=",
"Use `*=` operator",
OperatorPrecedence::Assign,
)),
"__ior__" => Some(Self::Operator(
"|=",
"Use `|=` operator",
OperatorPrecedence::Assign,
)),
"__ipow__" => Some(Self::Operator(
"**=",
"Use `**=` operator",
OperatorPrecedence::Assign,
)),
"__irshift__" => Some(Self::Operator(
">>=",
"Use `>>=` operator",
OperatorPrecedence::Assign,
)),
"__isub__" => Some(Self::Operator(
"-=",
"Use `-=` operator",
OperatorPrecedence::Assign,
)),
"__itruediv__" => Some(Self::Operator(
"/=",
"Use `/=` operator",
OperatorPrecedence::Assign,
)),
"__ixor__" => Some(Self::Operator(
"^=",
"Use `^=` operator",
OperatorPrecedence::Assign,
)),
"__le__" => Some(Self::Operator(
"<=",
"Use `<=` operator",
OperatorPrecedence::ComparisonsMembershipIdentity,
)),
"__lshift__" => Some(Self::Operator(
"<<",
"Use `<<` operator",
OperatorPrecedence::LeftRightShift,
)),
"__lt__" => Some(Self::Operator(
"<",
"Use `<` operator",
OperatorPrecedence::ComparisonsMembershipIdentity,
)),
"__mod__" => Some(Self::Operator(
"%",
"Use `%` operator",
OperatorPrecedence::MulDivRemain,
)),
"__mul__" => Some(Self::Operator(
"*",
"Use `*` operator",
OperatorPrecedence::MulDivRemain,
)),
"__ne__" => Some(Self::Operator(
"!=",
"Use `!=` operator",
OperatorPrecedence::ComparisonsMembershipIdentity,
)),
"__or__" => Some(Self::Operator(
"|",
"Use `|` operator",
OperatorPrecedence::BitXorOr,
)),
"__rshift__" => Some(Self::Operator(
">>",
"Use `>>` operator",
OperatorPrecedence::LeftRightShift,
)),
"__sub__" => Some(Self::Operator(
"-",
"Use `-` operator",
OperatorPrecedence::AddSub,
)),
"__truediv__" => Some(Self::Operator(
"/",
"Use `/` operator",
OperatorPrecedence::MulDivRemain,
)),
"__xor__" => Some(Self::Operator(
"^",
"Use `^` operator",
OperatorPrecedence::BitXorOr,
)),
"__radd__" => Some(Self::ROperator("+", "Use `+` operator")),
"__rand__" => Some(Self::ROperator("&", "Use `&` operator")),
"__rfloordiv__" => Some(Self::ROperator("//", "Use `//` operator")),
"__rlshift__" => Some(Self::ROperator("<<", "Use `<<` operator")),
"__rmod__" => Some(Self::ROperator("%", "Use `%` operator")),
"__rmul__" => Some(Self::ROperator("*", "Use `*` operator")),
"__ror__" => Some(Self::ROperator("|", "Use `|` operator")),
"__rrshift__" => Some(Self::ROperator(">>", "Use `>>` operator")),
"__rsub__" => Some(Self::ROperator("-", "Use `-` operator")),
"__rtruediv__" => Some(Self::ROperator("/", "Use `/` operator")),
"__rxor__" => Some(Self::ROperator("^", "Use `^` operator")),
"__radd__" => Some(Self::ROperator(
"+",
"Use `+` operator",
OperatorPrecedence::AddSub,
)),
"__rand__" => Some(Self::ROperator(
"&",
"Use `&` operator",
OperatorPrecedence::BitAnd,
)),
"__rfloordiv__" => Some(Self::ROperator(
"//",
"Use `//` operator",
OperatorPrecedence::MulDivRemain,
)),
"__rlshift__" => Some(Self::ROperator(
"<<",
"Use `<<` operator",
OperatorPrecedence::LeftRightShift,
)),
"__rmod__" => Some(Self::ROperator(
"%",
"Use `%` operator",
OperatorPrecedence::MulDivRemain,
)),
"__rmul__" => Some(Self::ROperator(
"*",
"Use `*` operator",
OperatorPrecedence::MulDivRemain,
)),
"__ror__" => Some(Self::ROperator(
"|",
"Use `|` operator",
OperatorPrecedence::BitXorOr,
)),
"__rrshift__" => Some(Self::ROperator(
">>",
"Use `>>` operator",
OperatorPrecedence::LeftRightShift,
)),
"__rsub__" => Some(Self::ROperator(
"-",
"Use `-` operator",
OperatorPrecedence::AddSub,
)),
"__rtruediv__" => Some(Self::ROperator(
"/",
"Use `/` operator",
OperatorPrecedence::MulDivRemain,
)),
"__rxor__" => Some(Self::ROperator(
"^",
"Use `^` operator",
OperatorPrecedence::BitXorOr,
)),
"__aiter__" => Some(Self::Builtin("aiter", "Use `aiter()` builtin")),
"__anext__" => Some(Self::Builtin("anext", "Use `anext()` builtin")),
@ -391,23 +573,166 @@ fn in_dunder_method_definition(semantic: &SemanticModel) -> bool {
})
}
/// Returns `true` if the [`Expr`] can be represented without parentheses.
fn can_be_represented_without_parentheses(expr: &Expr) -> bool {
expr.is_attribute_expr()
|| expr.is_name_expr()
|| expr.is_literal_expr()
|| expr.is_call_expr()
|| expr.is_lambda_expr()
|| expr.is_if_expr()
|| expr.is_generator_expr()
|| expr.is_subscript_expr()
|| expr.is_starred_expr()
|| expr.is_slice_expr()
|| expr.is_dict_expr()
|| expr.is_dict_comp_expr()
|| expr.is_list_expr()
|| expr.is_list_comp_expr()
|| expr.is_tuple_expr()
|| expr.is_set_comp_expr()
|| expr.is_set_expr()
/// Represents the precedence levels for Python expressions.
/// Variants at the top have lower precedence and variants at the bottom have
/// higher precedence.
///
/// See: <https://docs.python.org/3/reference/expressions.html#operator-precedence>
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum OperatorPrecedence {
/// The lowest (virtual) precedence level
None,
/// Precedence of `yield` and `yield from` expressions.
Yield,
/// Precedence of assignment expressions (`name := expr`).
Assign,
/// Precedence of starred expressions (`*expr`).
Starred,
/// Precedence of lambda expressions (`lambda args: expr`).
Lambda,
/// Precedence of if/else expressions (`expr if cond else expr`).
IfElse,
/// Precedence of boolean `or` expressions.
Or,
/// Precedence of boolean `and` expressions.
And,
/// Precedence of boolean `not` expressions.
Not,
/// Precedence of comparisons (`<`, `<=`, `>`, `>=`, `!=`, `==`),
/// memberships (`in`, `not in`) and identity tests (`is`, `is not`).
ComparisonsMembershipIdentity,
/// Precedence of bitwise `|` and `^` operators.
BitXorOr,
/// Precedence of bitwise `&` operator.
BitAnd,
/// Precedence of left and right shift expressions (`<<`, `>>`).
LeftRightShift,
/// Precedence of addition and subtraction expressions (`+`, `-`).
AddSub,
/// Precedence of multiplication (`*`), matrix multiplication (`@`), division (`/`),
/// floor division (`//`) and remainder (`%`) expressions.
MulDivRemain,
/// Precedence of unary positive (`+`), negative (`-`), and bitwise NOT (`~`) expressions.
PosNegBitNot,
/// Precedence of exponentiation expressions (`**`).
Exponent,
/// Precedence of `await` expressions.
Await,
/// Precedence of call expressions (`()`), attribute access (`.`), and subscript (`[]`) expressions.
CallAttribute,
/// Precedence of atomic expressions (literals, names, containers).
Atomic,
}
impl OperatorPrecedence {
fn from_expr(expr: &Expr) -> Self {
match expr {
// Binding or parenthesized expression, list display, dictionary display, set display
Expr::Tuple(_)
| Expr::Dict(_)
| Expr::Set(_)
| Expr::ListComp(_)
| Expr::List(_)
| Expr::SetComp(_)
| Expr::DictComp(_)
| Expr::Generator(_)
| Expr::Name(_)
| Expr::StringLiteral(_)
| Expr::BytesLiteral(_)
| Expr::NumberLiteral(_)
| Expr::BooleanLiteral(_)
| Expr::NoneLiteral(_)
| Expr::EllipsisLiteral(_)
| Expr::FString(_) => Self::Atomic,
// Subscription, slicing, call, attribute reference
Expr::Attribute(_) | Expr::Subscript(_) | Expr::Call(_) | Expr::Slice(_) => {
Self::CallAttribute
}
// Await expression
Expr::Await(_) => Self::Await,
// Exponentiation **
// Handled below along with other binary operators
// Unary operators: +x, -x, ~x (except boolean not)
Expr::UnaryOp(operator) => match operator.op {
UnaryOp::UAdd | UnaryOp::USub | UnaryOp::Invert => Self::PosNegBitNot,
UnaryOp::Not => Self::Not,
},
// Math binary ops
Expr::BinOp(binary_operation) => Self::from(binary_operation.op),
// Comparisons: <, <=, >, >=, ==, !=, in, not in, is, is not
Expr::Compare(_) => Self::ComparisonsMembershipIdentity,
// Boolean not
// Handled above in unary operators
// Boolean operations: and, or
Expr::BoolOp(bool_op) => Self::from(bool_op.op),
// Conditional expressions: x if y else z
Expr::If(_) => Self::IfElse,
// Lambda expressions
Expr::Lambda(_) => Self::Lambda,
// Unpacking also omitted in the docs, but has almost the lowest precedence,
// except for assignment & yield expressions. E.g. `[*(v := [1,2])]` is valid
// but `[*v := [1,2]] would fail on incorrect syntax because * will associate
// `v` before the assignment.
Expr::Starred(_) => Self::Starred,
// Assignment expressions (aka named)
Expr::Named(_) => Self::Assign,
// Although omitted in docs, yield expressions may be used inside an expression
// but must be parenthesized. So for our purposes we assume they just have
// the lowest "real" precedence.
Expr::Yield(_) | Expr::YieldFrom(_) => Self::Yield,
// Not a real python expression, so treat as lowest as well
Expr::IpyEscapeCommand(_) => Self::None,
}
}
}
impl From<&Expr> for OperatorPrecedence {
fn from(expr: &Expr) -> Self {
Self::from_expr(expr)
}
}
impl From<Operator> for OperatorPrecedence {
fn from(operator: Operator) -> Self {
match operator {
// Multiplication, matrix multiplication, division, floor division, remainder:
// *, @, /, //, %
Operator::Mult
| Operator::MatMult
| Operator::Div
| Operator::Mod
| Operator::FloorDiv => Self::MulDivRemain,
// Addition, subtraction
Operator::Add | Operator::Sub => Self::AddSub,
// Bitwise shifts: <<, >>
Operator::LShift | Operator::RShift => Self::LeftRightShift,
// Bitwise operations: &, ^, |
Operator::BitAnd => Self::BitAnd,
Operator::BitXor | Operator::BitOr => Self::BitXorOr,
// Exponentiation **
Operator::Pow => Self::Exponent,
}
}
}
impl From<BoolOp> for OperatorPrecedence {
fn from(operator: BoolOp) -> Self {
match operator {
BoolOp::And => Self::And,
BoolOp::Or => Self::Or,
}
}
}

View File

@ -750,370 +750,455 @@ unnecessary_dunder_call.py:49:7: PLC2801 Unnecessary dunder call to `__call__`
49 | print(a.__call__()) # PLC2801 (no fix, intentional)
| ^^^^^^^^^^^^ PLC2801
50 |
51 | # Lambda expressions
51 | class Foo:
|
unnecessary_dunder_call.py:52:16: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
unnecessary_dunder_call.py:63:1: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
51 | # Lambda expressions
52 | blah = lambda: a.__add__(1) # PLC2801
62 | foo = Foo(1)
63 | foo.__add__(2).get_v() # PLC2801
| ^^^^^^^^^^^^^^ PLC2801
|
= help: Use `+` operator
Unsafe fix
60 60 | return self.v
61 61 |
62 62 | foo = Foo(1)
63 |-foo.__add__(2).get_v() # PLC2801
63 |+(foo + 2).get_v() # PLC2801
64 64 |
65 65 |
66 66 | # Lambda expressions
unnecessary_dunder_call.py:67:16: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
66 | # Lambda expressions
67 | blah = lambda: a.__add__(1) # PLC2801
| ^^^^^^^^^^^^ PLC2801
53 |
54 | # If expressions
68 |
69 | # If expressions
|
= help: Use `+` operator
Unsafe fix
49 49 | print(a.__call__()) # PLC2801 (no fix, intentional)
50 50 |
51 51 | # Lambda expressions
52 |-blah = lambda: a.__add__(1) # PLC2801
52 |+blah = lambda: a + 1 # PLC2801
53 53 |
54 54 | # If expressions
55 55 | print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
64 64 |
65 65 |
66 66 | # Lambda expressions
67 |-blah = lambda: a.__add__(1) # PLC2801
67 |+blah = lambda: a + 1 # PLC2801
68 68 |
69 69 | # If expressions
70 70 | print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
unnecessary_dunder_call.py:55:7: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
unnecessary_dunder_call.py:70:7: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
54 | # If expressions
55 | print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
69 | # If expressions
70 | print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
| ^^^^^^^^^^^^ PLC2801
56 |
57 | # Dict/Set/List/Tuple
71 |
72 | # Dict/Set/List/Tuple
|
= help: Use `+` operator
Unsafe fix
52 52 | blah = lambda: a.__add__(1) # PLC2801
53 53 |
54 54 | # If expressions
55 |-print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
55 |+print(a + 1 if a > 0 else a.__sub__(1)) # PLC2801
56 56 |
57 57 | # Dict/Set/List/Tuple
58 58 | print({"a": a.__add__(1)}) # PLC2801
67 67 | blah = lambda: a.__add__(1) # PLC2801
68 68 |
69 69 | # If expressions
70 |-print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
70 |+print(a + 1 if a > 0 else a.__sub__(1)) # PLC2801
71 71 |
72 72 | # Dict/Set/List/Tuple
73 73 | print({"a": a.__add__(1)}) # PLC2801
unnecessary_dunder_call.py:55:34: PLC2801 [*] Unnecessary dunder call to `__sub__`. Use `-` operator.
unnecessary_dunder_call.py:70:34: PLC2801 [*] Unnecessary dunder call to `__sub__`. Use `-` operator.
|
54 | # If expressions
55 | print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
69 | # If expressions
70 | print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
| ^^^^^^^^^^^^ PLC2801
56 |
57 | # Dict/Set/List/Tuple
71 |
72 | # Dict/Set/List/Tuple
|
= help: Use `-` operator
Unsafe fix
52 52 | blah = lambda: a.__add__(1) # PLC2801
53 53 |
54 54 | # If expressions
55 |-print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
55 |+print(a.__add__(1) if a > 0 else a - 1) # PLC2801
56 56 |
57 57 | # Dict/Set/List/Tuple
58 58 | print({"a": a.__add__(1)}) # PLC2801
67 67 | blah = lambda: a.__add__(1) # PLC2801
68 68 |
69 69 | # If expressions
70 |-print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
70 |+print(a.__add__(1) if a > 0 else a - 1) # PLC2801
71 71 |
72 72 | # Dict/Set/List/Tuple
73 73 | print({"a": a.__add__(1)}) # PLC2801
unnecessary_dunder_call.py:58:13: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
unnecessary_dunder_call.py:73:13: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
57 | # Dict/Set/List/Tuple
58 | print({"a": a.__add__(1)}) # PLC2801
72 | # Dict/Set/List/Tuple
73 | print({"a": a.__add__(1)}) # PLC2801
| ^^^^^^^^^^^^ PLC2801
59 | print({a.__add__(1)}) # PLC2801
60 | print([a.__add__(1)]) # PLC2801
74 | print({a.__add__(1)}) # PLC2801
75 | print([a.__add__(1)]) # PLC2801
|
= help: Use `+` operator
Unsafe fix
55 55 | print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
56 56 |
57 57 | # Dict/Set/List/Tuple
58 |-print({"a": a.__add__(1)}) # PLC2801
58 |+print({"a": a + 1}) # PLC2801
59 59 | print({a.__add__(1)}) # PLC2801
60 60 | print([a.__add__(1)]) # PLC2801
61 61 | print((a.__add__(1),)) # PLC2801
70 70 | print(a.__add__(1) if a > 0 else a.__sub__(1)) # PLC2801
71 71 |
72 72 | # Dict/Set/List/Tuple
73 |-print({"a": a.__add__(1)}) # PLC2801
73 |+print({"a": (a + 1)}) # PLC2801
74 74 | print({a.__add__(1)}) # PLC2801
75 75 | print([a.__add__(1)]) # PLC2801
76 76 | print((a.__add__(1),)) # PLC2801
unnecessary_dunder_call.py:59:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
unnecessary_dunder_call.py:74:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
57 | # Dict/Set/List/Tuple
58 | print({"a": a.__add__(1)}) # PLC2801
59 | print({a.__add__(1)}) # PLC2801
72 | # Dict/Set/List/Tuple
73 | print({"a": a.__add__(1)}) # PLC2801
74 | print({a.__add__(1)}) # PLC2801
| ^^^^^^^^^^^^ PLC2801
60 | print([a.__add__(1)]) # PLC2801
61 | print((a.__add__(1),)) # PLC2801
75 | print([a.__add__(1)]) # PLC2801
76 | print((a.__add__(1),)) # PLC2801
|
= help: Use `+` operator
Unsafe fix
56 56 |
57 57 | # Dict/Set/List/Tuple
58 58 | print({"a": a.__add__(1)}) # PLC2801
59 |-print({a.__add__(1)}) # PLC2801
59 |+print({a + 1}) # PLC2801
60 60 | print([a.__add__(1)]) # PLC2801
61 61 | print((a.__add__(1),)) # PLC2801
62 62 |
71 71 |
72 72 | # Dict/Set/List/Tuple
73 73 | print({"a": a.__add__(1)}) # PLC2801
74 |-print({a.__add__(1)}) # PLC2801
74 |+print({(a + 1)}) # PLC2801
75 75 | print([a.__add__(1)]) # PLC2801
76 76 | print((a.__add__(1),)) # PLC2801
77 77 |
unnecessary_dunder_call.py:60:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
unnecessary_dunder_call.py:75:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
58 | print({"a": a.__add__(1)}) # PLC2801
59 | print({a.__add__(1)}) # PLC2801
60 | print([a.__add__(1)]) # PLC2801
73 | print({"a": a.__add__(1)}) # PLC2801
74 | print({a.__add__(1)}) # PLC2801
75 | print([a.__add__(1)]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
61 | print((a.__add__(1),)) # PLC2801
76 | print((a.__add__(1),)) # PLC2801
|
= help: Use `+` operator
Unsafe fix
57 57 | # Dict/Set/List/Tuple
58 58 | print({"a": a.__add__(1)}) # PLC2801
59 59 | print({a.__add__(1)}) # PLC2801
60 |-print([a.__add__(1)]) # PLC2801
60 |+print([a + 1]) # PLC2801
61 61 | print((a.__add__(1),)) # PLC2801
62 62 |
63 63 | # Comprehension variants
72 72 | # Dict/Set/List/Tuple
73 73 | print({"a": a.__add__(1)}) # PLC2801
74 74 | print({a.__add__(1)}) # PLC2801
75 |-print([a.__add__(1)]) # PLC2801
75 |+print([(a + 1)]) # PLC2801
76 76 | print((a.__add__(1),)) # PLC2801
77 77 |
78 78 | # Comprehension variants
unnecessary_dunder_call.py:61:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
unnecessary_dunder_call.py:76:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
59 | print({a.__add__(1)}) # PLC2801
60 | print([a.__add__(1)]) # PLC2801
61 | print((a.__add__(1),)) # PLC2801
74 | print({a.__add__(1)}) # PLC2801
75 | print([a.__add__(1)]) # PLC2801
76 | print((a.__add__(1),)) # PLC2801
| ^^^^^^^^^^^^ PLC2801
62 |
63 | # Comprehension variants
77 |
78 | # Comprehension variants
|
= help: Use `+` operator
Unsafe fix
58 58 | print({"a": a.__add__(1)}) # PLC2801
59 59 | print({a.__add__(1)}) # PLC2801
60 60 | print([a.__add__(1)]) # PLC2801
61 |-print((a.__add__(1),)) # PLC2801
61 |+print((a + 1,)) # PLC2801
62 62 |
63 63 | # Comprehension variants
64 64 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
73 73 | print({"a": a.__add__(1)}) # PLC2801
74 74 | print({a.__add__(1)}) # PLC2801
75 75 | print([a.__add__(1)]) # PLC2801
76 |-print((a.__add__(1),)) # PLC2801
76 |+print(((a + 1),)) # PLC2801
77 77 |
78 78 | # Comprehension variants
79 79 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
unnecessary_dunder_call.py:64:11: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
unnecessary_dunder_call.py:79:11: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
63 | # Comprehension variants
64 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
78 | # Comprehension variants
79 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
| ^^^^^^^^^^^^ PLC2801
65 | print({i.__add__(1) for i in range(5)}) # PLC2801
66 | print([i.__add__(1) for i in range(5)]) # PLC2801
80 | print({i.__add__(1) for i in range(5)}) # PLC2801
81 | print([i.__add__(1) for i in range(5)]) # PLC2801
|
= help: Use `+` operator
Unsafe fix
61 61 | print((a.__add__(1),)) # PLC2801
62 62 |
63 63 | # Comprehension variants
64 |-print({i: i.__add__(1) for i in range(5)}) # PLC2801
64 |+print({i: i + 1 for i in range(5)}) # PLC2801
65 65 | print({i.__add__(1) for i in range(5)}) # PLC2801
66 66 | print([i.__add__(1) for i in range(5)]) # PLC2801
67 67 | print((i.__add__(1) for i in range(5))) # PLC2801
unnecessary_dunder_call.py:65:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
63 | # Comprehension variants
64 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
65 | print({i.__add__(1) for i in range(5)}) # PLC2801
| ^^^^^^^^^^^^ PLC2801
66 | print([i.__add__(1) for i in range(5)]) # PLC2801
67 | print((i.__add__(1) for i in range(5))) # PLC2801
|
= help: Use `+` operator
Unsafe fix
62 62 |
63 63 | # Comprehension variants
64 64 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
65 |-print({i.__add__(1) for i in range(5)}) # PLC2801
65 |+print({i + 1 for i in range(5)}) # PLC2801
66 66 | print([i.__add__(1) for i in range(5)]) # PLC2801
67 67 | print((i.__add__(1) for i in range(5))) # PLC2801
68 68 |
unnecessary_dunder_call.py:66:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
64 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
65 | print({i.__add__(1) for i in range(5)}) # PLC2801
66 | print([i.__add__(1) for i in range(5)]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
67 | print((i.__add__(1) for i in range(5))) # PLC2801
|
= help: Use `+` operator
Unsafe fix
63 63 | # Comprehension variants
64 64 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
65 65 | print({i.__add__(1) for i in range(5)}) # PLC2801
66 |-print([i.__add__(1) for i in range(5)]) # PLC2801
66 |+print([i + 1 for i in range(5)]) # PLC2801
67 67 | print((i.__add__(1) for i in range(5))) # PLC2801
68 68 |
69 69 | # Generators
unnecessary_dunder_call.py:67:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
65 | print({i.__add__(1) for i in range(5)}) # PLC2801
66 | print([i.__add__(1) for i in range(5)]) # PLC2801
67 | print((i.__add__(1) for i in range(5))) # PLC2801
| ^^^^^^^^^^^^ PLC2801
68 |
69 | # Generators
|
= help: Use `+` operator
Unsafe fix
64 64 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
65 65 | print({i.__add__(1) for i in range(5)}) # PLC2801
66 66 | print([i.__add__(1) for i in range(5)]) # PLC2801
67 |-print((i.__add__(1) for i in range(5))) # PLC2801
67 |+print((i + 1 for i in range(5))) # PLC2801
68 68 |
69 69 | # Generators
70 70 | gen = (i.__add__(1) for i in range(5)) # PLC2801
unnecessary_dunder_call.py:70:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
69 | # Generators
70 | gen = (i.__add__(1) for i in range(5)) # PLC2801
| ^^^^^^^^^^^^ PLC2801
71 | print(next(gen))
|
= help: Use `+` operator
Unsafe fix
67 67 | print((i.__add__(1) for i in range(5))) # PLC2801
68 68 |
69 69 | # Generators
70 |-gen = (i.__add__(1) for i in range(5)) # PLC2801
70 |+gen = (i + 1 for i in range(5)) # PLC2801
71 71 | print(next(gen))
72 72 |
73 73 | # Subscripts
unnecessary_dunder_call.py:74:13: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
73 | # Subscripts
74 | print({"a": a.__add__(1)}["a"]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
75 |
76 | # Starred
|
= help: Use `+` operator
Unsafe fix
71 71 | print(next(gen))
72 72 |
73 73 | # Subscripts
74 |-print({"a": a.__add__(1)}["a"]) # PLC2801
74 |+print({"a": a + 1}["a"]) # PLC2801
75 75 |
76 76 | # Starred
77 77 | print(*[a.__add__(1)]) # PLC2801
unnecessary_dunder_call.py:77:9: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
76 | # Starred
77 | print(*[a.__add__(1)]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
78 |
79 | # Slices
|
= help: Use `+` operator
Unsafe fix
74 74 | print({"a": a.__add__(1)}["a"]) # PLC2801
75 75 |
76 76 | # Starred
77 |-print(*[a.__add__(1)]) # PLC2801
77 |+print(*[a + 1]) # PLC2801
78 78 |
79 79 | # Slices
80 80 | print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
76 76 | print((a.__add__(1),)) # PLC2801
77 77 |
78 78 | # Comprehension variants
79 |-print({i: i.__add__(1) for i in range(5)}) # PLC2801
79 |+print({i: (i + 1) for i in range(5)}) # PLC2801
80 80 | print({i.__add__(1) for i in range(5)}) # PLC2801
81 81 | print([i.__add__(1) for i in range(5)]) # PLC2801
82 82 | print((i.__add__(1) for i in range(5))) # PLC2801
unnecessary_dunder_call.py:80:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
79 | # Slices
80 | print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
78 | # Comprehension variants
79 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
80 | print({i.__add__(1) for i in range(5)}) # PLC2801
| ^^^^^^^^^^^^ PLC2801
81 | print([i.__add__(1) for i in range(5)]) # PLC2801
82 | print((i.__add__(1) for i in range(5))) # PLC2801
|
= help: Use `+` operator
Unsafe fix
77 77 | print(*[a.__add__(1)]) # PLC2801
78 78 |
79 79 | # Slices
80 |-print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
80 |+print([a + 1, a.__sub__(1)][0:1]) # PLC2801
81 81 |
82 82 |
83 83 | class Thing:
77 77 |
78 78 | # Comprehension variants
79 79 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
80 |-print({i.__add__(1) for i in range(5)}) # PLC2801
80 |+print({(i + 1) for i in range(5)}) # PLC2801
81 81 | print([i.__add__(1) for i in range(5)]) # PLC2801
82 82 | print((i.__add__(1) for i in range(5))) # PLC2801
83 83 |
unnecessary_dunder_call.py:80:22: PLC2801 [*] Unnecessary dunder call to `__sub__`. Use `-` operator.
unnecessary_dunder_call.py:81:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
79 | # Slices
80 | print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
79 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
80 | print({i.__add__(1) for i in range(5)}) # PLC2801
81 | print([i.__add__(1) for i in range(5)]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
82 | print((i.__add__(1) for i in range(5))) # PLC2801
|
= help: Use `-` operator
= help: Use `+` operator
Unsafe fix
77 77 | print(*[a.__add__(1)]) # PLC2801
78 78 |
79 79 | # Slices
80 |-print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
80 |+print([a.__add__(1), a - 1][0:1]) # PLC2801
81 81 |
82 82 |
83 83 | class Thing:
78 78 | # Comprehension variants
79 79 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
80 80 | print({i.__add__(1) for i in range(5)}) # PLC2801
81 |-print([i.__add__(1) for i in range(5)]) # PLC2801
81 |+print([(i + 1) for i in range(5)]) # PLC2801
82 82 | print((i.__add__(1) for i in range(5))) # PLC2801
83 83 |
84 84 | # Generators
unnecessary_dunder_call.py:92:16: PLC2801 Unnecessary dunder call to `__getattribute__`. Access attribute directly or use getattr built-in function.
unnecessary_dunder_call.py:82:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
91 | def do_thing(self, item):
92 | return object.__getattribute__(self, item) # PLC2801
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLC2801
93 |
94 | def use_descriptor(self, item):
80 | print({i.__add__(1) for i in range(5)}) # PLC2801
81 | print([i.__add__(1) for i in range(5)]) # PLC2801
82 | print((i.__add__(1) for i in range(5))) # PLC2801
| ^^^^^^^^^^^^ PLC2801
83 |
84 | # Generators
|
= help: Access attribute directly or use getattr built-in function
= help: Use `+` operator
unnecessary_dunder_call.py:104:1: PLC2801 [*] Unnecessary dunder call to `__contains__`. Use `in` operator.
Unsafe fix
79 79 | print({i: i.__add__(1) for i in range(5)}) # PLC2801
80 80 | print({i.__add__(1) for i in range(5)}) # PLC2801
81 81 | print([i.__add__(1) for i in range(5)]) # PLC2801
82 |-print((i.__add__(1) for i in range(5))) # PLC2801
82 |+print(((i + 1) for i in range(5))) # PLC2801
83 83 |
84 84 | # Generators
85 85 | gen = (i.__add__(1) for i in range(5)) # PLC2801
unnecessary_dunder_call.py:85:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
84 | # Generators
85 | gen = (i.__add__(1) for i in range(5)) # PLC2801
| ^^^^^^^^^^^^ PLC2801
86 | print(next(gen))
|
= help: Use `+` operator
Unsafe fix
82 82 | print((i.__add__(1) for i in range(5))) # PLC2801
83 83 |
84 84 | # Generators
85 |-gen = (i.__add__(1) for i in range(5)) # PLC2801
85 |+gen = ((i + 1) for i in range(5)) # PLC2801
86 86 | print(next(gen))
87 87 |
88 88 | # Subscripts
unnecessary_dunder_call.py:89:13: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
88 | # Subscripts
89 | print({"a": a.__add__(1)}["a"]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
90 | # https://github.com/astral-sh/ruff/issues/15745
91 | print("x".__add__("y")[0]) # PLC2801
|
= help: Use `+` operator
Unsafe fix
86 86 | print(next(gen))
87 87 |
88 88 | # Subscripts
89 |-print({"a": a.__add__(1)}["a"]) # PLC2801
89 |+print({"a": (a + 1)}["a"]) # PLC2801
90 90 | # https://github.com/astral-sh/ruff/issues/15745
91 91 | print("x".__add__("y")[0]) # PLC2801
92 92 |
unnecessary_dunder_call.py:91:7: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
89 | print({"a": a.__add__(1)}["a"]) # PLC2801
90 | # https://github.com/astral-sh/ruff/issues/15745
91 | print("x".__add__("y")[0]) # PLC2801
| ^^^^^^^^^^^^^^^^ PLC2801
92 |
93 | # Starred
|
= help: Use `+` operator
Unsafe fix
88 88 | # Subscripts
89 89 | print({"a": a.__add__(1)}["a"]) # PLC2801
90 90 | # https://github.com/astral-sh/ruff/issues/15745
91 |-print("x".__add__("y")[0]) # PLC2801
91 |+print(("x" + "y")[0]) # PLC2801
92 92 |
93 93 | # Starred
94 94 | print(*[a.__add__(1)]) # PLC2801
unnecessary_dunder_call.py:94:9: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
93 | # Starred
94 | print(*[a.__add__(1)]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
95 |
96 | list1 = [1, 2, 3]
|
= help: Use `+` operator
Unsafe fix
91 91 | print("x".__add__("y")[0]) # PLC2801
92 92 |
93 93 | # Starred
94 |-print(*[a.__add__(1)]) # PLC2801
94 |+print(*[(a + 1)]) # PLC2801
95 95 |
96 96 | list1 = [1, 2, 3]
97 97 | list2 = [4, 5, 6]
unnecessary_dunder_call.py:98:9: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
102 | blah = dict[{"a": 1}.__delitem__("a")] # OK
103 |
104 | "abc".__contains__("a")
96 | list1 = [1, 2, 3]
97 | list2 = [4, 5, 6]
98 | print([*list1.__add__(list2)]) # PLC2801
| ^^^^^^^^^^^^^^^^^^^^ PLC2801
99 |
100 | # Slices
|
= help: Use `+` operator
Unsafe fix
95 95 |
96 96 | list1 = [1, 2, 3]
97 97 | list2 = [4, 5, 6]
98 |-print([*list1.__add__(list2)]) # PLC2801
98 |+print([*list1 + list2]) # PLC2801
99 99 |
100 100 | # Slices
101 101 | print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
unnecessary_dunder_call.py:101:8: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
100 | # Slices
101 | print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
102 |
103 | # Attribute access
|
= help: Use `+` operator
Unsafe fix
98 98 | print([*list1.__add__(list2)]) # PLC2801
99 99 |
100 100 | # Slices
101 |-print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
101 |+print([(a + 1), a.__sub__(1)][0:1]) # PLC2801
102 102 |
103 103 | # Attribute access
104 104 | # https://github.com/astral-sh/ruff/issues/15745
unnecessary_dunder_call.py:101:22: PLC2801 [*] Unnecessary dunder call to `__sub__`. Use `-` operator.
|
100 | # Slices
101 | print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
| ^^^^^^^^^^^^ PLC2801
102 |
103 | # Attribute access
|
= help: Use `-` operator
Unsafe fix
98 98 | print([*list1.__add__(list2)]) # PLC2801
99 99 |
100 100 | # Slices
101 |-print([a.__add__(1), a.__sub__(1)][0:1]) # PLC2801
101 |+print([a.__add__(1), (a - 1)][0:1]) # PLC2801
102 102 |
103 103 | # Attribute access
104 104 | # https://github.com/astral-sh/ruff/issues/15745
unnecessary_dunder_call.py:105:7: PLC2801 [*] Unnecessary dunder call to `__add__`. Use `+` operator.
|
103 | # Attribute access
104 | # https://github.com/astral-sh/ruff/issues/15745
105 | print(1j.__add__(1.0).real) # PLC2801
| ^^^^^^^^^^^^^^^ PLC2801
106 |
107 | class Thing:
|
= help: Use `+` operator
Unsafe fix
102 102 |
103 103 | # Attribute access
104 104 | # https://github.com/astral-sh/ruff/issues/15745
105 |-print(1j.__add__(1.0).real) # PLC2801
105 |+print((1j + 1.0).real) # PLC2801
106 106 |
107 107 | class Thing:
108 108 | def __init__(self, stuff: Any) -> None:
unnecessary_dunder_call.py:116:16: PLC2801 Unnecessary dunder call to `__getattribute__`. Access attribute directly or use getattr built-in function.
|
115 | def do_thing(self, item):
116 | return object.__getattribute__(self, item) # PLC2801
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLC2801
117 |
118 | def use_descriptor(self, item):
|
= help: Access attribute directly or use getattr built-in function
unnecessary_dunder_call.py:128:1: PLC2801 [*] Unnecessary dunder call to `__contains__`. Use `in` operator.
|
126 | blah = dict[{"a": 1}.__delitem__("a")] # OK
127 |
128 | "abc".__contains__("a")
| ^^^^^^^^^^^^^^^^^^^^^^^ PLC2801
105 |
106 | # https://github.com/astral-sh/ruff/issues/14597
129 |
130 | # https://github.com/astral-sh/ruff/issues/14597
|
= help: Use `in` operator
Unsafe fix
101 101 |
102 102 | blah = dict[{"a": 1}.__delitem__("a")] # OK
103 103 |
104 |-"abc".__contains__("a")
104 |+"a" in "abc"
105 105 |
106 106 | # https://github.com/astral-sh/ruff/issues/14597
107 107 | assert "abc".__str__() == "abc"
125 125 |
126 126 | blah = dict[{"a": 1}.__delitem__("a")] # OK
127 127 |
128 |-"abc".__contains__("a")
128 |+"a" in "abc"
129 129 |
130 130 | # https://github.com/astral-sh/ruff/issues/14597
131 131 | assert "abc".__str__() == "abc"
unnecessary_dunder_call.py:107:8: PLC2801 [*] Unnecessary dunder call to `__str__`. Use `str()` builtin.
unnecessary_dunder_call.py:131:8: PLC2801 [*] Unnecessary dunder call to `__str__`. Use `str()` builtin.
|
106 | # https://github.com/astral-sh/ruff/issues/14597
107 | assert "abc".__str__() == "abc"
130 | # https://github.com/astral-sh/ruff/issues/14597
131 | assert "abc".__str__() == "abc"
| ^^^^^^^^^^^^^^^ PLC2801
|
= help: Use `str()` builtin
Unsafe fix
104 104 | "abc".__contains__("a")
105 105 |
106 106 | # https://github.com/astral-sh/ruff/issues/14597
107 |-assert "abc".__str__() == "abc"
107 |+assert str("abc") == "abc"
128 128 | "abc".__contains__("a")
129 129 |
130 130 | # https://github.com/astral-sh/ruff/issues/14597
131 |-assert "abc".__str__() == "abc"
131 |+assert str("abc") == "abc"