mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:25:17 +00:00
Avoid recommending __slots__
for classes that inherit from more than namedtuple
(#12531)
## Summary Closes https://github.com/astral-sh/ruff/issues/11887.
This commit is contained in:
parent
998bfe0847
commit
1fe4a5faed
3 changed files with 50 additions and 21 deletions
|
@ -1,4 +1,5 @@
|
|||
from collections import namedtuple
|
||||
from enum import Enum
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
|
@ -20,3 +21,15 @@ class Good(namedtuple("foo", ["str", "int"])): # OK
|
|||
|
||||
class Good(NamedTuple): # Ok
|
||||
pass
|
||||
|
||||
|
||||
class Good(namedtuple("foo", ["str", "int"]), Enum):
|
||||
pass
|
||||
|
||||
|
||||
class UnusualButStillBad(namedtuple("foo", ["str", "int"]), NamedTuple("foo", [("x", int, "y", int)])):
|
||||
pass
|
||||
|
||||
|
||||
class UnusualButStillBad(namedtuple("foo", ["str", "int"]), object):
|
||||
pass
|
||||
|
|
|
@ -92,23 +92,25 @@ pub(crate) fn no_slots_in_namedtuple_subclass(
|
|||
}
|
||||
}
|
||||
|
||||
/// If the class has a call-based namedtuple in its bases,
|
||||
/// return the kind of namedtuple it is
|
||||
/// (either `collections.namedtuple()`, or `typing.NamedTuple()`).
|
||||
/// Else, return `None`.
|
||||
/// If the class's bases consist solely of named tuples, return the kind of named tuple
|
||||
/// (either `collections.namedtuple()`, or `typing.NamedTuple()`). Otherwise, return `None`.
|
||||
fn namedtuple_base(bases: &[Expr], semantic: &SemanticModel) -> Option<NamedTupleKind> {
|
||||
let mut kind = None;
|
||||
for base in bases {
|
||||
let Expr::Call(ast::ExprCall { func, .. }) = base else {
|
||||
continue;
|
||||
};
|
||||
let Some(qualified_name) = semantic.resolve_qualified_name(func) else {
|
||||
continue;
|
||||
};
|
||||
match qualified_name.segments() {
|
||||
["collections", "namedtuple"] => return Some(NamedTupleKind::Collections),
|
||||
["typing", "NamedTuple"] => return Some(NamedTupleKind::Typing),
|
||||
_ => continue,
|
||||
if let Expr::Call(ast::ExprCall { func, .. }) = base {
|
||||
// Ex) `collections.namedtuple()`
|
||||
let qualified_name = semantic.resolve_qualified_name(func)?;
|
||||
match qualified_name.segments() {
|
||||
["collections", "namedtuple"] => kind = kind.or(Some(NamedTupleKind::Collections)),
|
||||
["typing", "NamedTuple"] => kind = kind.or(Some(NamedTupleKind::Typing)),
|
||||
// Ex) `enum.Enum`
|
||||
_ => return None,
|
||||
}
|
||||
} else if !semantic.match_builtin_expr(base, "object") {
|
||||
// Allow inheriting from `object`.
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
||||
None
|
||||
kind
|
||||
}
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/flake8_slots/mod.rs
|
||||
---
|
||||
SLOT002.py:5:7: SLOT002 Subclasses of `collections.namedtuple()` should define `__slots__`
|
||||
SLOT002.py:6:7: SLOT002 Subclasses of `collections.namedtuple()` should define `__slots__`
|
||||
|
|
||||
5 | class Bad(namedtuple("foo", ["str", "int"])): # SLOT002
|
||||
6 | class Bad(namedtuple("foo", ["str", "int"])): # SLOT002
|
||||
| ^^^ SLOT002
|
||||
6 | pass
|
||||
7 | pass
|
||||
|
|
||||
|
||||
SLOT002.py:9:7: SLOT002 Subclasses of call-based `typing.NamedTuple()` should define `__slots__`
|
||||
SLOT002.py:10:7: SLOT002 Subclasses of call-based `typing.NamedTuple()` should define `__slots__`
|
||||
|
|
||||
9 | class UnusualButStillBad(NamedTuple("foo", [("x", int, "y", int)])): # SLOT002
|
||||
10 | class UnusualButStillBad(NamedTuple("foo", [("x", int, "y", int)])): # SLOT002
|
||||
| ^^^^^^^^^^^^^^^^^^ SLOT002
|
||||
10 | pass
|
||||
11 | pass
|
||||
|
|
||||
|
||||
SLOT002.py:30:7: SLOT002 Subclasses of `collections.namedtuple()` should define `__slots__`
|
||||
|
|
||||
30 | class UnusualButStillBad(namedtuple("foo", ["str", "int"]), NamedTuple("foo", [("x", int, "y", int)])):
|
||||
| ^^^^^^^^^^^^^^^^^^ SLOT002
|
||||
31 | pass
|
||||
|
|
||||
|
||||
SLOT002.py:34:7: SLOT002 Subclasses of `collections.namedtuple()` should define `__slots__`
|
||||
|
|
||||
34 | class UnusualButStillBad(namedtuple("foo", ["str", "int"]), object):
|
||||
| ^^^^^^^^^^^^^^^^^^ SLOT002
|
||||
35 | pass
|
||||
|
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue