Skip to content

Commit 4739f84

Browse files
Fix FP for no-member: function attributes from decorator (#9308)
1 parent 511354a commit 4739f84

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Avoid false positives for ``no-member`` involving function
2+
attributes supplied by decorators.
3+
4+
Closes #9246

pylint/checkers/typecheck.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,7 @@ def visit_assignattr(self, node: nodes.AssignAttr) -> None:
10601060
def visit_delattr(self, node: nodes.DelAttr) -> None:
10611061
self.visit_attribute(node)
10621062

1063-
# pylint: disable = too-many-branches
1063+
# pylint: disable = too-many-branches, too-many-statements
10641064
@only_required_for_messages("no-member", "c-extension-no-member")
10651065
def visit_attribute(
10661066
self, node: nodes.Attribute | nodes.AssignAttr | nodes.DelAttr
@@ -1128,6 +1128,12 @@ def visit_attribute(
11281128
except astroid.DuplicateBasesError:
11291129
continue
11301130
except astroid.NotFoundError:
1131+
# Avoid false positive in case a decorator supplies member.
1132+
if (
1133+
isinstance(owner, (astroid.FunctionDef, astroid.BoundMethod))
1134+
and owner.decorators
1135+
):
1136+
continue
11311137
# This can't be moved before the actual .getattr call,
11321138
# because there can be more values inferred and we are
11331139
# stopping after the first one which has the attribute in question.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""Attributes supplied by a decorator."""
2+
3+
from functools import lru_cache
4+
5+
6+
class SomeClass: # pylint: disable=too-few-public-methods
7+
"""https://github.com/pylint-dev/pylint/issues/9246"""
8+
@classmethod
9+
@lru_cache
10+
def __cached_fun(cls, arg: int) -> str:
11+
return str(arg)
12+
13+
@classmethod
14+
def cache_clear(cls):
15+
"""__cached_fun()'s @cache decorator supplies cache_clear()."""
16+
cls.__cached_fun.cache_clear()

0 commit comments

Comments
 (0)