mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 21:05:08 +00:00
[pylint
] Ignore __slots__
with dynamic values (#11488)
## Summary Closes https://github.com/astral-sh/ruff/issues/11333.
This commit is contained in:
parent
3476e2f359
commit
aa906b9c75
2 changed files with 41 additions and 6 deletions
|
@ -82,3 +82,16 @@ class Foo:
|
|||
@qux.setter
|
||||
def qux(self, value):
|
||||
self.bar = value / 2
|
||||
|
||||
|
||||
class StudentG:
|
||||
names = ("surname",)
|
||||
__slots__ = (*names, "a")
|
||||
|
||||
def __init__(self, name, surname):
|
||||
self.name = name
|
||||
self.surname = surname # [assigning-non-slot]
|
||||
self.setup()
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
|
|
@ -98,6 +98,8 @@ impl Ranged for AttributeAssignment<'_> {
|
|||
}
|
||||
|
||||
/// Return a list of attributes that are assigned to but not included in `__slots__`.
|
||||
///
|
||||
/// If the `__slots__` attribute cannot be statically determined, returns an empty vector.
|
||||
fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
|
||||
// First, collect all the attributes that are assigned to `__slots__`.
|
||||
let mut slots = FxHashSet::default();
|
||||
|
@ -110,7 +112,13 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
|
|||
};
|
||||
|
||||
if id == "__slots__" {
|
||||
slots.extend(slots_attributes(value));
|
||||
for attribute in slots_attributes(value) {
|
||||
if let Some(attribute) = attribute {
|
||||
slots.insert(attribute);
|
||||
} else {
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +133,13 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
|
|||
};
|
||||
|
||||
if id == "__slots__" {
|
||||
slots.extend(slots_attributes(value));
|
||||
for attribute in slots_attributes(value) {
|
||||
if let Some(attribute) = attribute {
|
||||
slots.insert(attribute);
|
||||
} else {
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +150,13 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
|
|||
};
|
||||
|
||||
if id == "__slots__" {
|
||||
slots.extend(slots_attributes(value));
|
||||
for attribute in slots_attributes(value) {
|
||||
if let Some(attribute) = attribute {
|
||||
slots.insert(attribute);
|
||||
} else {
|
||||
return vec![];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -237,12 +257,14 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
|
|||
}
|
||||
|
||||
/// Return an iterator over the attributes enumerated in the given `__slots__` value.
|
||||
fn slots_attributes(expr: &Expr) -> impl Iterator<Item = &str> {
|
||||
///
|
||||
/// If an attribute can't be statically determined, it will be `None`.
|
||||
fn slots_attributes(expr: &Expr) -> impl Iterator<Item = Option<&str>> {
|
||||
// Ex) `__slots__ = ("name",)`
|
||||
let elts_iter = match expr {
|
||||
Expr::Tuple(ast::ExprTuple { elts, .. })
|
||||
| Expr::List(ast::ExprList { elts, .. })
|
||||
| Expr::Set(ast::ExprSet { elts, .. }) => Some(elts.iter().filter_map(|elt| match elt {
|
||||
| Expr::Set(ast::ExprSet { elts, .. }) => Some(elts.iter().map(|elt| match elt {
|
||||
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => Some(value.to_str()),
|
||||
_ => None,
|
||||
})),
|
||||
|
@ -251,7 +273,7 @@ fn slots_attributes(expr: &Expr) -> impl Iterator<Item = &str> {
|
|||
|
||||
// Ex) `__slots__ = {"name": ...}`
|
||||
let keys_iter = match expr {
|
||||
Expr::Dict(dict) => Some(dict.iter_keys().filter_map(|key| match key {
|
||||
Expr::Dict(dict) => Some(dict.iter_keys().map(|key| match key {
|
||||
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => Some(value.to_str()),
|
||||
_ => None,
|
||||
})),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue