mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-30 13:51:37 +00:00
Ignore non-abstract class attributes when enforcing B024 (#11210)
## Summary I think the check included here does make sense, but I don't see why we would allow it if a value is provided for the attribute -- since, in that case, isn't it _not_ abstract? Closes: https://github.com/astral-sh/ruff/issues/11208.
This commit is contained in:
parent
c6dcf3502b
commit
c5adbf17da
3 changed files with 27 additions and 9 deletions
|
@ -115,25 +115,25 @@ class non_keyword_abcmeta_2(abc.ABCMeta): # safe
|
|||
|
||||
|
||||
# very invalid code, but that's up to mypy et al to check
|
||||
class keyword_abc_1(metaclass=ABC): # safe
|
||||
class keyword_abc_1(metaclass=ABC): # incorrect but outside scope of this check
|
||||
def method(self):
|
||||
foo()
|
||||
|
||||
|
||||
class keyword_abc_2(metaclass=abc.ABC): # safe
|
||||
class keyword_abc_2(metaclass=abc.ABC): # incorrect but outside scope of this check
|
||||
def method(self):
|
||||
foo()
|
||||
|
||||
|
||||
class abc_set_class_variable_1(ABC): # safe
|
||||
class abc_set_class_variable_1(ABC): # safe (abstract attribute)
|
||||
foo: int
|
||||
|
||||
|
||||
class abc_set_class_variable_2(ABC): # safe
|
||||
class abc_set_class_variable_2(ABC): # error (not an abstract attribute)
|
||||
foo = 2
|
||||
|
||||
|
||||
class abc_set_class_variable_3(ABC): # safe
|
||||
class abc_set_class_variable_3(ABC): # error (not an abstract attribute)
|
||||
foo: int = 2
|
||||
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ impl Violation for AbstractBaseClassWithoutAbstractMethod {
|
|||
format!("`{name}` is an abstract base class, but it has no abstract methods")
|
||||
}
|
||||
}
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for empty methods in abstract base classes without an abstract
|
||||
/// decorator.
|
||||
|
@ -156,8 +157,13 @@ pub(crate) fn abstract_base_class(
|
|||
let mut has_abstract_method = false;
|
||||
for stmt in body {
|
||||
// https://github.com/PyCQA/flake8-bugbear/issues/293
|
||||
// Ignore abc's that declares a class attribute that must be set
|
||||
if let Stmt::AnnAssign(_) | Stmt::Assign(_) = stmt {
|
||||
// If an ABC declares an attribute by providing a type annotation
|
||||
// but does not actually assign a value for that attribute,
|
||||
// assume it is intended to be an "abstract attribute"
|
||||
if matches!(
|
||||
stmt,
|
||||
Stmt::AnnAssign(ast::StmtAnnAssign { value: None, .. })
|
||||
) {
|
||||
has_abstract_method = true;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,20 @@ B024.py:92:7: B024 `notabc_Base_1` is an abstract base class, but it has no abst
|
|||
94 | foo()
|
||||
|
|
||||
|
||||
B024.py:132:7: B024 `abc_set_class_variable_2` is an abstract base class, but it has no abstract methods
|
||||
|
|
||||
132 | class abc_set_class_variable_2(ABC): # error (not an abstract attribute)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ B024
|
||||
133 | foo = 2
|
||||
|
|
||||
|
||||
B024.py:136:7: B024 `abc_set_class_variable_3` is an abstract base class, but it has no abstract methods
|
||||
|
|
||||
136 | class abc_set_class_variable_3(ABC): # error (not an abstract attribute)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ B024
|
||||
137 | foo: int = 2
|
||||
|
|
||||
|
||||
B024.py:141:7: B024 `abc_set_class_variable_4` is an abstract base class, but it has no abstract methods
|
||||
|
|
||||
140 | # this doesn't actually declare a class variable, it's just an expression
|
||||
|
@ -48,5 +62,3 @@ B024.py:141:7: B024 `abc_set_class_variable_4` is an abstract base class, but it
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^ B024
|
||||
142 | foo
|
||||
|
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue