mirror of https://github.com/astral-sh/ruff
Don't trigger `eq-without-hash` when `__hash__` is explicitly set to `None` (#6739)
This commit is contained in:
parent
c0df99b965
commit
37f4920e1e
|
|
@ -1,10 +1,11 @@
|
||||||
class Person:
|
class Person: # [eq-without-hash]
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.name = "monty"
|
self.name = "monty"
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return isinstance(other, Person) and other.name == self.name
|
return isinstance(other, Person) and other.name == self.name
|
||||||
|
|
||||||
|
# OK
|
||||||
class Language:
|
class Language:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.name = "python"
|
self.name = "python"
|
||||||
|
|
@ -14,3 +15,9 @@ class Language:
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash(self.name)
|
return hash(self.name)
|
||||||
|
|
||||||
|
class MyClass:
|
||||||
|
def __eq__(self, other):
|
||||||
|
return True
|
||||||
|
|
||||||
|
__hash__ = None
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use ruff_python_ast::{self as ast, Ranged, Stmt};
|
|
||||||
|
|
||||||
use ruff_diagnostics::{Diagnostic, Violation};
|
use ruff_diagnostics::{Diagnostic, Violation};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::helpers::is_const_none;
|
||||||
|
use ruff_python_ast::{self as ast, Expr, Ranged, Stmt};
|
||||||
|
|
||||||
use crate::checkers::ast::Checker;
|
use crate::checkers::ast::Checker;
|
||||||
|
|
||||||
|
|
@ -65,12 +65,29 @@ fn has_eq_without_hash(body: &[Stmt]) -> bool {
|
||||||
let mut has_hash = false;
|
let mut has_hash = false;
|
||||||
let mut has_eq = false;
|
let mut has_eq = false;
|
||||||
for statement in body {
|
for statement in body {
|
||||||
let Stmt::FunctionDef(ast::StmtFunctionDef { name, .. }) = statement else {
|
match statement {
|
||||||
continue;
|
Stmt::Assign(ast::StmtAssign { targets, value, .. }) => {
|
||||||
};
|
let [Expr::Name(ast::ExprName { id, .. })] = targets.as_slice() else {
|
||||||
match name.as_str() {
|
continue;
|
||||||
"__hash__" => has_hash = true,
|
};
|
||||||
"__eq__" => has_eq = true,
|
|
||||||
|
// Check if `__hash__` was explicitly set to `None`, as in:
|
||||||
|
// ```python
|
||||||
|
// class Class:
|
||||||
|
// def __eq__(self, other):
|
||||||
|
// return True
|
||||||
|
//
|
||||||
|
// __hash__ = None
|
||||||
|
// ```
|
||||||
|
if id == "__hash__" && is_const_none(value) {
|
||||||
|
has_hash = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stmt::FunctionDef(ast::StmtFunctionDef { name, .. }) => match name.as_str() {
|
||||||
|
"__hash__" => has_hash = true,
|
||||||
|
"__eq__" => has_eq = true,
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ source: crates/ruff/src/rules/pylint/mod.rs
|
||||||
---
|
---
|
||||||
eq_without_hash.py:1:7: PLW1641 Object does not implement `__hash__` method
|
eq_without_hash.py:1:7: PLW1641 Object does not implement `__hash__` method
|
||||||
|
|
|
|
||||||
1 | class Person:
|
1 | class Person: # [eq-without-hash]
|
||||||
| ^^^^^^ PLW1641
|
| ^^^^^^ PLW1641
|
||||||
2 | def __init__(self):
|
2 | def __init__(self):
|
||||||
3 | self.name = "monty"
|
3 | self.name = "monty"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue