mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:37 +00:00
Avoid recommending no-argument super in slots=True
dataclasses (#12530)
## Summary Closes https://github.com/astral-sh/ruff/issues/12506.
This commit is contained in:
parent
6f4db8675b
commit
998bfe0847
3 changed files with 67 additions and 1 deletions
|
@ -63,3 +63,19 @@ class MyClass(BaseClass):
|
||||||
InnerClass().method()
|
InnerClass().method()
|
||||||
|
|
||||||
defined_outside = defined_outside
|
defined_outside = defined_outside
|
||||||
|
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DataClass:
|
||||||
|
def normal(self):
|
||||||
|
super(DataClass, self).f() # Error
|
||||||
|
super().f() # OK
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True)
|
||||||
|
def normal(self):
|
||||||
|
super(DataClass, self).f() # OK
|
||||||
|
super().f() # OK (`TypeError` in practice)
|
||||||
|
|
|
@ -102,7 +102,9 @@ pub(crate) fn super_call_with_parameters(checker: &mut Checker, call: &ast::Expr
|
||||||
|
|
||||||
// Find the enclosing class definition (if any).
|
// Find the enclosing class definition (if any).
|
||||||
let Some(Stmt::ClassDef(ast::StmtClassDef {
|
let Some(Stmt::ClassDef(ast::StmtClassDef {
|
||||||
name: parent_name, ..
|
name: parent_name,
|
||||||
|
decorator_list,
|
||||||
|
..
|
||||||
})) = parents.find(|stmt| stmt.is_class_def_stmt())
|
})) = parents.find(|stmt| stmt.is_class_def_stmt())
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
|
@ -126,6 +128,36 @@ pub(crate) fn super_call_with_parameters(checker: &mut Checker, call: &ast::Expr
|
||||||
|
|
||||||
drop(parents);
|
drop(parents);
|
||||||
|
|
||||||
|
// If the class is an `@dataclass` with `slots=True`, calling `super()` without arguments raises
|
||||||
|
// a `TypeError`.
|
||||||
|
//
|
||||||
|
// See: https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass
|
||||||
|
if decorator_list.iter().any(|decorator| {
|
||||||
|
let Expr::Call(ast::ExprCall {
|
||||||
|
func, arguments, ..
|
||||||
|
}) = &decorator.expression
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if checker
|
||||||
|
.semantic()
|
||||||
|
.resolve_qualified_name(func)
|
||||||
|
.is_some_and(|name| name.segments() == ["dataclasses", "dataclass"])
|
||||||
|
{
|
||||||
|
arguments.find_keyword("slots").map_or(false, |keyword| {
|
||||||
|
matches!(
|
||||||
|
keyword.value,
|
||||||
|
Expr::BooleanLiteral(ast::ExprBooleanLiteral { value: true, .. })
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let mut diagnostic = Diagnostic::new(SuperCallWithParameters, call.arguments.range());
|
let mut diagnostic = Diagnostic::new(SuperCallWithParameters, call.arguments.range());
|
||||||
diagnostic.set_fix(Fix::unsafe_edit(Edit::deletion(
|
diagnostic.set_fix(Fix::unsafe_edit(Edit::deletion(
|
||||||
call.arguments.start() + TextSize::new(1),
|
call.arguments.start() + TextSize::new(1),
|
||||||
|
|
|
@ -107,4 +107,22 @@ UP008.py:50:18: UP008 [*] Use `super()` instead of `super(__class__, self)`
|
||||||
52 52 |
|
52 52 |
|
||||||
53 53 | outer_argument()
|
53 53 | outer_argument()
|
||||||
|
|
||||||
|
UP008.py:74:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
|
||||||
|
|
|
||||||
|
72 | class DataClass:
|
||||||
|
73 | def normal(self):
|
||||||
|
74 | super(DataClass, self).f() # Error
|
||||||
|
| ^^^^^^^^^^^^^^^^^ UP008
|
||||||
|
75 | super().f() # OK
|
||||||
|
|
|
||||||
|
= help: Remove `__super__` parameters
|
||||||
|
|
||||||
|
ℹ Unsafe fix
|
||||||
|
71 71 | @dataclass
|
||||||
|
72 72 | class DataClass:
|
||||||
|
73 73 | def normal(self):
|
||||||
|
74 |- super(DataClass, self).f() # Error
|
||||||
|
74 |+ super().f() # Error
|
||||||
|
75 75 | super().f() # OK
|
||||||
|
76 76 |
|
||||||
|
77 77 |
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue