Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include static and class methods in in abstract decorator list #4298

Merged
merged 1 commit into from
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Include abstractstaticmethod and abstractclassmethod in abstract deco…
…rators
  • Loading branch information
charliermarsh committed May 9, 2023
commit 745455143d29f84cb4a43d858d9f5e865926b8df
23 changes: 22 additions & 1 deletion crates/ruff/resources/test/fixtures/flake8_bugbear/B027.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
"""
import abc
from abc import ABC
from abc import abstractmethod, abstractproperty
from abc import (
abstractmethod,
abstractproperty,
abstractclassmethod,
abstractstaticmethod,
)
from abc import abstractmethod as notabstract
from abc import abstractproperty as notabstract_property

Expand Down Expand Up @@ -55,6 +60,22 @@ def abstract_5(self):
def abstract_6(self):
...

@abstractclassmethod
def abstract_7(self):
pass

@abc.abstractclassmethod
def abstract_8(self):
...

@abstractstaticmethod
def abstract_9(self):
pass

@abc.abstractstaticmethod
def abstract_10(self):
...

def body_1(self):
print("foo")
...
Expand Down
Original file line number Diff line number Diff line change
@@ -1,96 +1,96 @@
---
source: crates/ruff/src/rules/flake8_bugbear/mod.rs
---
B027.py:13:5: B027 [*] `AbstractClass.empty_1` is an empty method in an abstract base class, but has no abstract decorator
B027.py:18:5: B027 [*] `AbstractClass.empty_1` is an empty method in an abstract base class, but has no abstract decorator
|
13 | class AbstractClass(ABC):
14 | def empty_1(self): # error
18 | class AbstractClass(ABC):
19 | def empty_1(self): # error
| _____^
15 | | ...
20 | | ...
| |___________^ B027
16 |
17 | def empty_2(self): # error
21 |
22 | def empty_2(self): # error
|
= help: Add the `@abstractmethod` decorator

ℹ Suggested fix
10 10 |
11 11 |
12 12 | class AbstractClass(ABC):
13 |+ @notabstract
13 14 | def empty_1(self): # error
14 15 | ...
15 16 |
15 15 |
16 16 |
17 17 | class AbstractClass(ABC):
18 |+ @notabstract
18 19 | def empty_1(self): # error
19 20 | ...
20 21 |

B027.py:16:5: B027 [*] `AbstractClass.empty_2` is an empty method in an abstract base class, but has no abstract decorator
B027.py:21:5: B027 [*] `AbstractClass.empty_2` is an empty method in an abstract base class, but has no abstract decorator
|
16 | ...
17 |
18 | def empty_2(self): # error
21 | ...
22 |
23 | def empty_2(self): # error
| _____^
19 | | pass
24 | | pass
| |____________^ B027
20 |
21 | def empty_3(self): # error
25 |
26 | def empty_3(self): # error
|
= help: Add the `@abstractmethod` decorator

ℹ Suggested fix
13 13 | def empty_1(self): # error
14 14 | ...
15 15 |
16 |+ @notabstract
16 17 | def empty_2(self): # error
17 18 | pass
18 19 |
18 18 | def empty_1(self): # error
19 19 | ...
20 20 |
21 |+ @notabstract
21 22 | def empty_2(self): # error
22 23 | pass
23 24 |

B027.py:19:5: B027 [*] `AbstractClass.empty_3` is an empty method in an abstract base class, but has no abstract decorator
B027.py:24:5: B027 [*] `AbstractClass.empty_3` is an empty method in an abstract base class, but has no abstract decorator
|
19 | pass
20 |
21 | def empty_3(self): # error
24 | pass
25 |
26 | def empty_3(self): # error
| _____^
22 | | """docstring"""
23 | | ...
27 | | """docstring"""
28 | | ...
| |___________^ B027
24 |
25 | def empty_4(self): # error
29 |
30 | def empty_4(self): # error
|
= help: Add the `@abstractmethod` decorator

ℹ Suggested fix
16 16 | def empty_2(self): # error
17 17 | pass
18 18 |
19 |+ @notabstract
19 20 | def empty_3(self): # error
20 21 | """docstring"""
21 22 | ...
21 21 | def empty_2(self): # error
22 22 | pass
23 23 |
24 |+ @notabstract
24 25 | def empty_3(self): # error
25 26 | """docstring"""
26 27 | ...

B027.py:23:5: B027 [*] `AbstractClass.empty_4` is an empty method in an abstract base class, but has no abstract decorator
B027.py:28:5: B027 [*] `AbstractClass.empty_4` is an empty method in an abstract base class, but has no abstract decorator
|
23 | ...
24 |
25 | def empty_4(self): # error
28 | ...
29 |
30 | def empty_4(self): # error
| _____^
26 | | """multiple ellipsis/pass"""
27 | | ...
28 | | pass
29 | | ...
30 | | pass
31 | | """multiple ellipsis/pass"""
32 | | ...
33 | | pass
34 | | ...
35 | | pass
| |____________^ B027
31 |
32 | @notabstract
36 |
37 | @notabstract
|
= help: Add the `@abstractmethod` decorator

ℹ Suggested fix
20 20 | """docstring"""
21 21 | ...
22 22 |
23 |+ @notabstract
23 24 | def empty_4(self): # error
24 25 | """multiple ellipsis/pass"""
25 26 | ...
25 25 | """docstring"""
26 26 | ...
27 27 |
28 |+ @notabstract
28 29 | def empty_4(self): # error
29 30 | """multiple ellipsis/pass"""
30 31 | ...


14 changes: 11 additions & 3 deletions crates/ruff_python_semantic/src/analyze/visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,21 @@ pub fn is_override(ctx: &Context, decorator_list: &[Expr]) -> bool {
.any(|expr| ctx.match_typing_expr(map_callable(expr), "override"))
}

/// Returns `true` if a function definition is an `@abstractmethod`.
/// Returns `true` if a function definition is an abstract method based on its decorators.
pub fn is_abstract(ctx: &Context, decorator_list: &[Expr]) -> bool {
decorator_list.iter().any(|expr| {
ctx.resolve_call_path(map_callable(expr))
.map_or(false, |call_path| {
call_path.as_slice() == ["abc", "abstractmethod"]
|| call_path.as_slice() == ["abc", "abstractproperty"]
matches!(
call_path.as_slice(),
[
"abc",
"abstractmethod"
| "abstractclassmethod"
| "abstractstaticmethod"
| "abstractproperty"
]
)
})
})
}
Expand Down
Loading