mirror of https://github.com/astral-sh/ruff
[`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:
parent
b848afeae8
commit
15dd3b5ebd
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue