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
|
@qux.setter
|
||||||
def qux(self, value):
|
def qux(self, value):
|
||||||
self.bar = value / 2
|
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__`.
|
/// 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> {
|
fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
|
||||||
// First, collect all the attributes that are assigned to `__slots__`.
|
// First, collect all the attributes that are assigned to `__slots__`.
|
||||||
let mut slots = FxHashSet::default();
|
let mut slots = FxHashSet::default();
|
||||||
|
@ -110,7 +112,13 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if id == "__slots__" {
|
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__" {
|
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__" {
|
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.
|
/// 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",)`
|
// Ex) `__slots__ = ("name",)`
|
||||||
let elts_iter = match expr {
|
let elts_iter = match expr {
|
||||||
Expr::Tuple(ast::ExprTuple { elts, .. })
|
Expr::Tuple(ast::ExprTuple { elts, .. })
|
||||||
| Expr::List(ast::ExprList { 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()),
|
Expr::StringLiteral(ast::ExprStringLiteral { value, .. }) => Some(value.to_str()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})),
|
})),
|
||||||
|
@ -251,7 +273,7 @@ fn slots_attributes(expr: &Expr) -> impl Iterator<Item = &str> {
|
||||||
|
|
||||||
// Ex) `__slots__ = {"name": ...}`
|
// Ex) `__slots__ = {"name": ...}`
|
||||||
let keys_iter = match expr {
|
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()),
|
Some(Expr::StringLiteral(ast::ExprStringLiteral { value, .. })) => Some(value.to_str()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})),
|
})),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue