Skip to content

Commit

Permalink
Ignore non-abstract class attributes when enforcing B024 (#11210)
Browse files Browse the repository at this point in the history
## 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: #11208.
  • Loading branch information
charliermarsh authored Apr 30, 2024
1 parent c6dcf35 commit c5adbf1
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,25 +115,25 @@ def method(self):


# 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


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,24 @@ 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
141 | class abc_set_class_variable_4(ABC): # error
| ^^^^^^^^^^^^^^^^^^^^^^^^ B024
142 | foo
|


0 comments on commit c5adbf1

Please sign in to comment.