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

Fix false positive for inherit-non-class for generic Protocols #9108

Merged
merged 1 commit into from
Oct 4, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/9106.false_positive
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fixed false positive for ``inherit-non-class`` for generic Protocols.

Closes #9106
5 changes: 3 additions & 2 deletions pylint/checkers/classes/class_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -957,8 +957,9 @@ def _check_proper_bases(self, node: nodes.ClassDef) -> None:
ancestor = safe_infer(base)
if not ancestor:
continue
if isinstance(ancestor, astroid.Instance) and ancestor.is_subtype_of(
"builtins.type"
if isinstance(ancestor, astroid.Instance) and (
ancestor.is_subtype_of("builtins.type")
or ancestor.is_subtype_of(".Protocol")
):
continue

Expand Down
16 changes: 16 additions & 0 deletions tests/functional/i/inherit_non_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# pylint: disable=import-error, invalid-name, using-constant-test
# pylint: disable=missing-docstring, too-few-public-methods, useless-object-inheritance

from typing import Protocol, TypeVar
from missing import Missing

if 1:
Expand Down Expand Up @@ -101,3 +102,18 @@ class Child2(ParentBad[int]): # [inherit-non-class]
# Classes that don't implement '__class_getitem__' are marked as unsubscriptable
class Child3(Empty[int]): # [unsubscriptable-object]
pass


T = TypeVar("T")


class Channel(Protocol[T]):
"""A generic Protocol."""

async def get(self) -> T:
"""A get method using the generic."""


class DirectChannel(Channel[T]):
async def get(self) -> T:
"""An implementation of the generic."""
22 changes: 11 additions & 11 deletions tests/functional/i/inherit_non_class.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
inherit-non-class:21:0:21:9:Bad:Inheriting '1', which is not a class.:UNDEFINED
inherit-non-class:24:0:24:10:Bad1:"Inheriting 'lambda abc: 42', which is not a class.":UNDEFINED
inherit-non-class:27:0:27:10:Bad2:Inheriting 'object()', which is not a class.:UNDEFINED
inherit-non-class:30:0:30:10:Bad3:Inheriting 'return_class', which is not a class.:UNDEFINED
inherit-non-class:33:0:33:10:Bad4:Inheriting 'Empty()', which is not a class.:UNDEFINED
inherit-non-class:68:0:68:24:NotInheritableBool:Inheriting 'bool', which is not a class.:UNDEFINED
inherit-non-class:72:0:72:25:NotInheritableRange:Inheriting 'range', which is not a class.:UNDEFINED
inherit-non-class:76:0:76:25:NotInheritableSlice:Inheriting 'slice', which is not a class.:UNDEFINED
inherit-non-class:80:0:80:30:NotInheritableMemoryView:Inheriting 'memoryview', which is not a class.:UNDEFINED
inherit-non-class:98:0:98:12:Child2:Inheriting 'ParentBad[int]', which is not a class.:UNDEFINED
unsubscriptable-object:102:13:102:18:Child3:Value 'Empty' is unsubscriptable:UNDEFINED
inherit-non-class:22:0:22:9:Bad:Inheriting '1', which is not a class.:UNDEFINED
inherit-non-class:25:0:25:10:Bad1:"Inheriting 'lambda abc: 42', which is not a class.":UNDEFINED
inherit-non-class:28:0:28:10:Bad2:Inheriting 'object()', which is not a class.:UNDEFINED
inherit-non-class:31:0:31:10:Bad3:Inheriting 'return_class', which is not a class.:UNDEFINED
inherit-non-class:34:0:34:10:Bad4:Inheriting 'Empty()', which is not a class.:UNDEFINED
inherit-non-class:69:0:69:24:NotInheritableBool:Inheriting 'bool', which is not a class.:UNDEFINED
inherit-non-class:73:0:73:25:NotInheritableRange:Inheriting 'range', which is not a class.:UNDEFINED
inherit-non-class:77:0:77:25:NotInheritableSlice:Inheriting 'slice', which is not a class.:UNDEFINED
inherit-non-class:81:0:81:30:NotInheritableMemoryView:Inheriting 'memoryview', which is not a class.:UNDEFINED
inherit-non-class:99:0:99:12:Child2:Inheriting 'ParentBad[int]', which is not a class.:UNDEFINED
unsubscriptable-object:103:13:103:18:Child3:Value 'Empty' is unsubscriptable:UNDEFINED