Skip to content

Commit

Permalink
Respect abc decorators when classifying function types (#5315)
Browse files Browse the repository at this point in the history
Closes #5307.
  • Loading branch information
charliermarsh authored Jun 22, 2023
1 parent 5f88ff8 commit cdbd0bd
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 31 deletions.
8 changes: 6 additions & 2 deletions crates/ruff/resources/test/fixtures/pep8_naming/N805.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from abc import ABCMeta
import abc

import pydantic

Expand All @@ -19,6 +19,10 @@ def good_method(self):
def class_method(cls):
pass

@abc.abstractclassmethod
def abstract_class_method(cls):
pass

@staticmethod
def static_method(x):
return x
Expand All @@ -41,7 +45,7 @@ def __init_subclass__(self, default_name, **kwargs):
...


class MetaClass(ABCMeta):
class MetaClass(abc.ABCMeta):
def bad_method(self):
pass

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from abc import ABCMeta
import abc

import pydantic

Expand Down Expand Up @@ -34,6 +34,23 @@ def badAllowed(cls, my_field: str) -> str:
def stillBad(cls, my_field: str) -> str:
pass

@classmethod
def badAllowed(cls):
pass

@classmethod
def stillBad(cls):
pass

@abc.abstractclassmethod
def badAllowed(cls):
pass

@abc.abstractclassmethod
def stillBad(cls):
pass


class PosOnlyClass:
def badAllowed(this, blah, /, self, something: str):
pass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,29 @@ N805.py:12:30: N805 First argument of a method should be named `self`
13 | pass
|

N805.py:27:15: N805 First argument of a method should be named `self`
N805.py:31:15: N805 First argument of a method should be named `self`
|
26 | @pydantic.validator
27 | def lower(cls, my_field: str) -> str:
30 | @pydantic.validator
31 | def lower(cls, my_field: str) -> str:
| ^^^ N805
28 | pass
32 | pass
|

N805.py:31:15: N805 First argument of a method should be named `self`
N805.py:35:15: N805 First argument of a method should be named `self`
|
30 | @pydantic.validator("my_field")
31 | def lower(cls, my_field: str) -> str:
34 | @pydantic.validator("my_field")
35 | def lower(cls, my_field: str) -> str:
| ^^^ N805
32 | pass
36 | pass
|

N805.py:60:29: N805 First argument of a method should be named `self`
N805.py:64:29: N805 First argument of a method should be named `self`
|
58 | pass
59 |
60 | def bad_method_pos_only(this, blah, /, self, something: str):
62 | pass
63 |
64 | def bad_method_pos_only(this, blah, /, self, something: str):
| ^^^^ N805
61 | pass
65 | pass
|


Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ N805.py:12:30: N805 First argument of a method should be named `self`
13 | pass
|

N805.py:60:29: N805 First argument of a method should be named `self`
N805.py:64:29: N805 First argument of a method should be named `self`
|
58 | pass
59 |
60 | def bad_method_pos_only(this, blah, /, self, something: str):
62 | pass
63 |
64 | def bad_method_pos_only(this, blah, /, self, something: str):
| ^^^^ N805
61 | pass
65 | pass
|


Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ N805.py:34:18: N805 First argument of a method should be named `self`
35 | pass
|

N805.py:41:18: N805 First argument of a method should be named `self`
N805.py:58:18: N805 First argument of a method should be named `self`
|
39 | pass
40 |
41 | def stillBad(this, blah, /, self, something: str):
56 | pass
57 |
58 | def stillBad(this, blah, /, self, something: str):
| ^^^^ N805
42 | pass
59 | pass
|


12 changes: 7 additions & 5 deletions crates/ruff_python_semantic/src/analyze/function_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ pub fn classify(
semantic
.resolve_call_path(map_callable(&decorator.expression))
.map_or(false, |call_path| {
matches!(call_path.as_slice(), ["", "staticmethod"])
|| staticmethod_decorators
.iter()
.any(|decorator| call_path == from_qualified_name(decorator))
matches!(
call_path.as_slice(),
["", "staticmethod"] | ["abc", "abstractstaticmethod"]
) || staticmethod_decorators
.iter()
.any(|decorator| call_path == from_qualified_name(decorator))
})
}) {
FunctionType::StaticMethod
Expand All @@ -55,7 +57,7 @@ pub fn classify(
|| decorator_list.iter().any(|decorator| {
// The method is decorated with a class method decorator (like `@classmethod`).
semantic.resolve_call_path(map_callable(&decorator.expression)).map_or(false, |call_path| {
matches!(call_path.as_slice(), ["", "classmethod"]) ||
matches!(call_path.as_slice(), ["", "classmethod"] | ["abc", "abstractclassmethod"]) ||
classmethod_decorators
.iter()
.any(|decorator| call_path == from_qualified_name(decorator))
Expand Down

0 comments on commit cdbd0bd

Please sign in to comment.