Skip to content

Commit

Permalink
Ignore unnecessary dunder calls within dunder definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Jan 12, 2024
1 parent fee64b5 commit 8aafed0
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ def __init__(self, stuff: Any) -> None:
super().__init__() # OK
super().__class__(stuff=(1, 2, 3)) # OK

def __getattribute__(self, item):
return object.__getattribute__(self, item) # OK

def do_thing(self, item):
return object.__getattribute__(self, item) # PLC2801


blah = lambda: {"a": 1}.__delitem__("a") # OK

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::{self as ast, Expr};
use ruff_python_ast::{self as ast, Expr, Stmt};
use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged;

Expand Down Expand Up @@ -80,11 +80,17 @@ pub(crate) fn unnecessary_dunder_call(checker: &mut Checker, call: &ast::ExprCal
return;
}

// Ignore certain dunder methods used in lambda expressions.
// Ignore certain dunder method calls in lambda expressions. These methods would require
// rewriting as a statement, which is not possible in a lambda expression.
if allow_nested_expression(attr, checker.semantic()) {
return;
}

// Ignore dunder method calls within dunder methods definitions.
if in_dunder_method_definition(checker.semantic()) {
return;
}

// Ignore dunder methods used on `super`.
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
if checker.semantic().is_builtin("super") {
Expand Down Expand Up @@ -344,3 +350,13 @@ fn allow_nested_expression(dunder_name: &str, semantic: &SemanticModel) -> bool
| "__ior__"
)
}

/// Returns `true` if the [`SemanticModel`] is currently in a dunder method definition.
fn in_dunder_method_definition(semantic: &SemanticModel) -> bool {
semantic.current_statements().any(|statement| {
let Stmt::FunctionDef(func_def) = statement else {
return false;
};
func_def.name.starts_with("__") && func_def.name.ends_with("__")
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -321,4 +321,12 @@ unnecessary_dunder_call.py:19:7: PLC2801 Unnecessary dunder call to `__neg__`. M
|
= help: Multiply by -1 instead

unnecessary_dunder_call.py:31:16: PLC2801 Unnecessary dunder call to `__getattribute__`. Access attribute directly or use getattr built-in function.
|
30 | def do_thing(self, item):
31 | return object.__getattribute__(self, item) # PLC2801
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLC2801
|
= help: Access attribute directly or use getattr built-in function


0 comments on commit 8aafed0

Please sign in to comment.