mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 11:59:35 +00:00
Allow private accesses within special dunder methods (#4968)
This commit is contained in:
parent
58d08219e8
commit
775d247731
3 changed files with 134 additions and 75 deletions
|
@ -53,6 +53,9 @@ class Foo(metaclass=BazMeta):
|
|||
def __really_private_func(self, arg):
|
||||
super().__really_private_func(arg)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._private_thing == other._private_thing
|
||||
|
||||
|
||||
foo = Foo()
|
||||
|
||||
|
|
|
@ -75,6 +75,64 @@ pub(crate) fn private_member_access(checker: &mut Checker, expr: &Expr) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Ignore accesses on instances within special methods (e.g., `__eq__`).
|
||||
if let ScopeKind::Function(ast::StmtFunctionDef { name, .. }) =
|
||||
checker.semantic_model().scope().kind
|
||||
{
|
||||
if matches!(
|
||||
name.as_str(),
|
||||
"__lt__"
|
||||
| "__le__"
|
||||
| "__eq__"
|
||||
| "__ne__"
|
||||
| "__gt__"
|
||||
| "__ge__"
|
||||
| "__add__"
|
||||
| "__sub__"
|
||||
| "__mul__"
|
||||
| "__matmul__"
|
||||
| "__truediv__"
|
||||
| "__floordiv__"
|
||||
| "__mod__"
|
||||
| "__divmod__"
|
||||
| "__pow__"
|
||||
| "__lshift__"
|
||||
| "__rshift__"
|
||||
| "__and__"
|
||||
| "__xor__"
|
||||
| "__or__"
|
||||
| "__radd__"
|
||||
| "__rsub__"
|
||||
| "__rmul__"
|
||||
| "__rmatmul__"
|
||||
| "__rtruediv__"
|
||||
| "__rfloordiv__"
|
||||
| "__rmod__"
|
||||
| "__rdivmod__"
|
||||
| "__rpow__"
|
||||
| "__rlshift__"
|
||||
| "__rrshift__"
|
||||
| "__rand__"
|
||||
| "__rxor__"
|
||||
| "__ror__"
|
||||
| "__iadd__"
|
||||
| "__isub__"
|
||||
| "__imul__"
|
||||
| "__imatmul__"
|
||||
| "__itruediv__"
|
||||
| "__ifloordiv__"
|
||||
| "__imod__"
|
||||
| "__ipow__"
|
||||
| "__ilshift__"
|
||||
| "__irshift__"
|
||||
| "__iand__"
|
||||
| "__ixor__"
|
||||
| "__ior__"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = value.as_ref() {
|
||||
// Ignore `super()` calls.
|
||||
if let Some(call_path) = collect_call_path(func) {
|
||||
|
@ -82,43 +140,41 @@ pub(crate) fn private_member_access(checker: &mut Checker, expr: &Expr) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if let Some(call_path) = collect_call_path(value) {
|
||||
// Ignore `self` and `cls` accesses.
|
||||
if let Some(call_path) = collect_call_path(value) {
|
||||
if call_path.as_slice() == ["self"]
|
||||
|| call_path.as_slice() == ["cls"]
|
||||
|| call_path.as_slice() == ["mcs"]
|
||||
{
|
||||
return;
|
||||
}
|
||||
if call_path.as_slice() == ["self"]
|
||||
|| call_path.as_slice() == ["cls"]
|
||||
|| call_path.as_slice() == ["mcs"]
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore accesses on class members from _within_ the class.
|
||||
if checker
|
||||
.semantic_model()
|
||||
.scopes
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|scope| match &scope.kind {
|
||||
ScopeKind::Class(ast::StmtClassDef { name, .. }) => Some(name),
|
||||
_ => None,
|
||||
})
|
||||
.map_or(false, |name| {
|
||||
if call_path.as_slice() == [name.as_str()] {
|
||||
checker.semantic_model().find_binding(name).map_or(
|
||||
false,
|
||||
|binding| {
|
||||
// TODO(charlie): Could the name ever be bound to a
|
||||
// _different_ class here?
|
||||
binding.kind.is_class_definition()
|
||||
},
|
||||
)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Ignore accesses on class members from _within_ the class.
|
||||
if checker
|
||||
.semantic_model()
|
||||
.scopes
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|scope| match &scope.kind {
|
||||
ScopeKind::Class(ast::StmtClassDef { name, .. }) => Some(name),
|
||||
_ => None,
|
||||
})
|
||||
.map_or(false, |name| {
|
||||
if call_path.as_slice() == [name.as_str()] {
|
||||
checker
|
||||
.semantic_model()
|
||||
.find_binding(name)
|
||||
.map_or(false, |binding| {
|
||||
// TODO(charlie): Could the name ever be bound to a
|
||||
// _different_ class here?
|
||||
binding.kind.is_class_definition()
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,72 +40,72 @@ SLF001.py:43:12: SLF001 Private member accessed: `_private_thing`
|
|||
47 | return self.bar
|
||||
|
|
||||
|
||||
SLF001.py:59:7: SLF001 Private member accessed: `_private_thing`
|
||||
SLF001.py:62:7: SLF001 Private member accessed: `_private_thing`
|
||||
|
|
||||
59 | foo = Foo()
|
||||
60 |
|
||||
61 | print(foo._private_thing) # SLF001
|
||||
62 | foo = Foo()
|
||||
63 |
|
||||
64 | print(foo._private_thing) # SLF001
|
||||
| ^^^^^^^^^^^^^^^^^^ SLF001
|
||||
62 | print(foo.__really_private_thing) # SLF001
|
||||
63 | print(foo._private_func()) # SLF001
|
||||
65 | print(foo.__really_private_thing) # SLF001
|
||||
66 | print(foo._private_func()) # SLF001
|
||||
|
|
||||
|
||||
SLF001.py:60:7: SLF001 Private member accessed: `__really_private_thing`
|
||||
SLF001.py:63:7: SLF001 Private member accessed: `__really_private_thing`
|
||||
|
|
||||
60 | print(foo._private_thing) # SLF001
|
||||
61 | print(foo.__really_private_thing) # SLF001
|
||||
63 | print(foo._private_thing) # SLF001
|
||||
64 | print(foo.__really_private_thing) # SLF001
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ SLF001
|
||||
62 | print(foo._private_func()) # SLF001
|
||||
63 | print(foo.__really_private_func(1)) # SLF001
|
||||
65 | print(foo._private_func()) # SLF001
|
||||
66 | print(foo.__really_private_func(1)) # SLF001
|
||||
|
|
||||
|
||||
SLF001.py:61:7: SLF001 Private member accessed: `_private_func`
|
||||
SLF001.py:64:7: SLF001 Private member accessed: `_private_func`
|
||||
|
|
||||
61 | print(foo._private_thing) # SLF001
|
||||
62 | print(foo.__really_private_thing) # SLF001
|
||||
63 | print(foo._private_func()) # SLF001
|
||||
64 | print(foo._private_thing) # SLF001
|
||||
65 | print(foo.__really_private_thing) # SLF001
|
||||
66 | print(foo._private_func()) # SLF001
|
||||
| ^^^^^^^^^^^^^^^^^ SLF001
|
||||
64 | print(foo.__really_private_func(1)) # SLF001
|
||||
65 | print(foo.bar._private) # SLF001
|
||||
67 | print(foo.__really_private_func(1)) # SLF001
|
||||
68 | print(foo.bar._private) # SLF001
|
||||
|
|
||||
|
||||
SLF001.py:62:7: SLF001 Private member accessed: `__really_private_func`
|
||||
SLF001.py:65:7: SLF001 Private member accessed: `__really_private_func`
|
||||
|
|
||||
62 | print(foo.__really_private_thing) # SLF001
|
||||
63 | print(foo._private_func()) # SLF001
|
||||
64 | print(foo.__really_private_func(1)) # SLF001
|
||||
65 | print(foo.__really_private_thing) # SLF001
|
||||
66 | print(foo._private_func()) # SLF001
|
||||
67 | print(foo.__really_private_func(1)) # SLF001
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ SLF001
|
||||
65 | print(foo.bar._private) # SLF001
|
||||
66 | print(foo()._private_thing) # SLF001
|
||||
68 | print(foo.bar._private) # SLF001
|
||||
69 | print(foo()._private_thing) # SLF001
|
||||
|
|
||||
|
||||
SLF001.py:63:7: SLF001 Private member accessed: `_private`
|
||||
SLF001.py:66:7: SLF001 Private member accessed: `_private`
|
||||
|
|
||||
63 | print(foo._private_func()) # SLF001
|
||||
64 | print(foo.__really_private_func(1)) # SLF001
|
||||
65 | print(foo.bar._private) # SLF001
|
||||
66 | print(foo._private_func()) # SLF001
|
||||
67 | print(foo.__really_private_func(1)) # SLF001
|
||||
68 | print(foo.bar._private) # SLF001
|
||||
| ^^^^^^^^^^^^^^^^ SLF001
|
||||
66 | print(foo()._private_thing) # SLF001
|
||||
67 | print(foo()._private_thing__) # SLF001
|
||||
69 | print(foo()._private_thing) # SLF001
|
||||
70 | print(foo()._private_thing__) # SLF001
|
||||
|
|
||||
|
||||
SLF001.py:64:7: SLF001 Private member accessed: `_private_thing`
|
||||
SLF001.py:67:7: SLF001 Private member accessed: `_private_thing`
|
||||
|
|
||||
64 | print(foo.__really_private_func(1)) # SLF001
|
||||
65 | print(foo.bar._private) # SLF001
|
||||
66 | print(foo()._private_thing) # SLF001
|
||||
67 | print(foo.__really_private_func(1)) # SLF001
|
||||
68 | print(foo.bar._private) # SLF001
|
||||
69 | print(foo()._private_thing) # SLF001
|
||||
| ^^^^^^^^^^^^^^^^^^^^ SLF001
|
||||
67 | print(foo()._private_thing__) # SLF001
|
||||
70 | print(foo()._private_thing__) # SLF001
|
||||
|
|
||||
|
||||
SLF001.py:65:7: SLF001 Private member accessed: `_private_thing__`
|
||||
SLF001.py:68:7: SLF001 Private member accessed: `_private_thing__`
|
||||
|
|
||||
65 | print(foo.bar._private) # SLF001
|
||||
66 | print(foo()._private_thing) # SLF001
|
||||
67 | print(foo()._private_thing__) # SLF001
|
||||
68 | print(foo.bar._private) # SLF001
|
||||
69 | print(foo()._private_thing) # SLF001
|
||||
70 | print(foo()._private_thing__) # SLF001
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ SLF001
|
||||
68 |
|
||||
69 | print(foo.public_thing)
|
||||
71 |
|
||||
72 | print(foo.public_thing)
|
||||
|
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue