Respect abc decorators when classifying function types (#5315)

Closes #5307.
This commit is contained in:
Charlie Marsh 2023-06-22 15:52:36 -04:00 committed by GitHub
parent 5f88ff8a96
commit cdbd0bd5cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 32 deletions

View file

@ -1,4 +1,4 @@
from abc import ABCMeta import abc
import pydantic import pydantic
@ -19,6 +19,10 @@ class Class:
def class_method(cls): def class_method(cls):
pass pass
@abc.abstractclassmethod
def abstract_class_method(cls):
pass
@staticmethod @staticmethod
def static_method(x): def static_method(x):
return x return x
@ -41,7 +45,7 @@ class Class:
... ...
class MetaClass(ABCMeta): class MetaClass(abc.ABCMeta):
def bad_method(self): def bad_method(self):
pass pass

View file

@ -1,4 +1,4 @@
from abc import ABCMeta import abc
import pydantic import pydantic
@ -34,6 +34,23 @@ class Class:
def stillBad(cls, my_field: str) -> str: def stillBad(cls, my_field: str) -> str:
pass 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: class PosOnlyClass:
def badAllowed(this, blah, /, self, something: str): def badAllowed(this, blah, /, self, something: str):
pass pass

View file

@ -18,29 +18,29 @@ N805.py:12:30: N805 First argument of a method should be named `self`
13 | pass 13 | pass
| |
N805.py:27:15: N805 First argument of a method should be named `self`
|
26 | @pydantic.validator
27 | def lower(cls, my_field: str) -> str:
| ^^^ N805
28 | pass
|
N805.py:31: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`
| |
30 | @pydantic.validator("my_field") 30 | @pydantic.validator
31 | def lower(cls, my_field: str) -> str: 31 | def lower(cls, my_field: str) -> str:
| ^^^ N805 | ^^^ N805
32 | pass 32 | pass
| |
N805.py:60:29: N805 First argument of a method should be named `self` N805.py:35:15: N805 First argument of a method should be named `self`
| |
58 | pass 34 | @pydantic.validator("my_field")
59 | 35 | def lower(cls, my_field: str) -> str:
60 | def bad_method_pos_only(this, blah, /, self, something: str): | ^^^ N805
36 | pass
|
N805.py:64:29: N805 First argument of a method should be named `self`
|
62 | pass
63 |
64 | def bad_method_pos_only(this, blah, /, self, something: str):
| ^^^^ N805 | ^^^^ N805
61 | pass 65 | pass
| |

View file

@ -18,13 +18,13 @@ N805.py:12:30: N805 First argument of a method should be named `self`
13 | pass 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 62 | pass
59 | 63 |
60 | def bad_method_pos_only(this, blah, /, self, something: str): 64 | def bad_method_pos_only(this, blah, /, self, something: str):
| ^^^^ N805 | ^^^^ N805
61 | pass 65 | pass
| |

View file

@ -35,13 +35,13 @@ N805.py:34:18: N805 First argument of a method should be named `self`
35 | pass 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 56 | pass
40 | 57 |
41 | def stillBad(this, blah, /, self, something: str): 58 | def stillBad(this, blah, /, self, something: str):
| ^^^^ N805 | ^^^^ N805
42 | pass 59 | pass
| |

View file

@ -35,10 +35,12 @@ pub fn classify(
semantic semantic
.resolve_call_path(map_callable(&decorator.expression)) .resolve_call_path(map_callable(&decorator.expression))
.map_or(false, |call_path| { .map_or(false, |call_path| {
matches!(call_path.as_slice(), ["", "staticmethod"]) matches!(
|| staticmethod_decorators call_path.as_slice(),
.iter() ["", "staticmethod"] | ["abc", "abstractstaticmethod"]
.any(|decorator| call_path == from_qualified_name(decorator)) ) || staticmethod_decorators
.iter()
.any(|decorator| call_path == from_qualified_name(decorator))
}) })
}) { }) {
FunctionType::StaticMethod FunctionType::StaticMethod
@ -55,7 +57,7 @@ pub fn classify(
|| decorator_list.iter().any(|decorator| { || decorator_list.iter().any(|decorator| {
// The method is decorated with a class method decorator (like `@classmethod`). // The method is decorated with a class method decorator (like `@classmethod`).
semantic.resolve_call_path(map_callable(&decorator.expression)).map_or(false, |call_path| { 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 classmethod_decorators
.iter() .iter()
.any(|decorator| call_path == from_qualified_name(decorator)) .any(|decorator| call_path == from_qualified_name(decorator))