From 27e56c405df1b350b7a74d38cbb311d93c8bf63b Mon Sep 17 00:00:00 2001 From: clavedeluna Date: Thu, 24 Nov 2022 09:17:23 -0300 Subject: [PATCH] make protocols be defined as abstract --- doc/whatsnew/fragments/7209.false_positive | 3 ++ pylint/checkers/utils.py | 4 +++ .../functional/p/protocol_classes_abstract.py | 36 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 doc/whatsnew/fragments/7209.false_positive create mode 100644 tests/functional/p/protocol_classes_abstract.py diff --git a/doc/whatsnew/fragments/7209.false_positive b/doc/whatsnew/fragments/7209.false_positive new file mode 100644 index 00000000000..a1ba0c5d8ad --- /dev/null +++ b/doc/whatsnew/fragments/7209.false_positive @@ -0,0 +1,3 @@ +Fixes false positive ``abstract-method`` on Protocol classes. + +Closes #7209 diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py index a2a0c1b378f..65df5096d00 100644 --- a/pylint/checkers/utils.py +++ b/pylint/checkers/utils.py @@ -1167,6 +1167,10 @@ def class_is_abstract(node: nodes.ClassDef) -> bool: """Return true if the given class node should be considered as an abstract class. """ + # Protocol classes are considered "abstract" + if is_protocol_class(node): + return True + # Only check for explicit metaclass=ABCMeta on this specific class meta = node.declared_metaclass() if meta is not None: diff --git a/tests/functional/p/protocol_classes_abstract.py b/tests/functional/p/protocol_classes_abstract.py new file mode 100644 index 00000000000..95f74246e7a --- /dev/null +++ b/tests/functional/p/protocol_classes_abstract.py @@ -0,0 +1,36 @@ +"""Test that classes inheriting from protocols should not warn about abstract-method.""" +# pylint: disable=too-few-public-methods,disallowed-name,invalid-name +from abc import abstractmethod +from typing import Protocol, Literal + + +class FooProtocol(Protocol): + """Foo Protocol""" + + @abstractmethod + def foo(self) -> Literal["foo"]: + """foo method""" + + def foo_no_abstract(self) -> Literal["foo"]: + """foo not abstract method""" + +class BarProtocol(Protocol): + """Bar Protocol""" + @abstractmethod + def bar(self) -> Literal["bar"]: + """bar method""" + + + +class FooBarProtocol(FooProtocol, BarProtocol, Protocol): + """FooBar Protocol""" + + +class FooBar(FooBarProtocol): + """FooBar object""" + + def bar(self) -> Literal["bar"]: + return "bar" + + def foo(self) -> Literal["foo"]: + return "foo"