Skip to content

Commit 129c730

Browse files
Fix #1555: Fix false negative for no-member when assigning instance attribute to itself (#5544)
Co-authored-by: Daniël van Noord <[email protected]>
1 parent fe57cc7 commit 129c730

File tree

5 files changed

+65
-9
lines changed

5 files changed

+65
-9
lines changed

ChangeLog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ Release date: TBA
99
..
1010
Put new features here and also in 'doc/whatsnew/2.14.rst'
1111

12+
* Fix false negative for ``no-member`` when attempting to assign an instance
13+
attribute to itself without any prior assignment.
1214

15+
Closes #1555
1316

1417
..
1518
Insert your changelog randomly, it will reduce merge conflicts

doc/whatsnew/2.14.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ Extensions
2323

2424
Other Changes
2525
=============
26+
27+
* Fix false negative for ``no-member`` when attempting to assign an instance
28+
attribute to itself without any prior assignment.
29+
30+
Closes #1555

pylint/checkers/typecheck.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,15 +1007,7 @@ def visit_attribute(self, node: nodes.Attribute) -> None:
10071007
return
10081008

10091009
try:
1010-
if not [
1011-
n
1012-
for n in owner.getattr(node.attrname)
1013-
if not isinstance(n.statement(future=True), nodes.AugAssign)
1014-
]:
1015-
missingattr.add((owner, name))
1016-
continue
1017-
except astroid.exceptions.StatementMissing:
1018-
continue
1010+
attr_nodes = owner.getattr(node.attrname)
10191011
except AttributeError:
10201012
continue
10211013
except astroid.DuplicateBasesError:
@@ -1039,6 +1031,24 @@ def visit_attribute(self, node: nodes.Attribute) -> None:
10391031
continue
10401032
missingattr.add((owner, name))
10411033
continue
1034+
else:
1035+
for attr_node in attr_nodes:
1036+
attr_parent = attr_node.parent
1037+
# Skip augmented assignments
1038+
try:
1039+
if isinstance(
1040+
attr_node.statement(future=True), nodes.AugAssign
1041+
):
1042+
continue
1043+
except astroid.exceptions.StatementMissing:
1044+
break
1045+
# Skip self-referencing assignments
1046+
if attr_parent is node.parent:
1047+
continue
1048+
break
1049+
else:
1050+
missingattr.add((owner, name))
1051+
continue
10421052
# stop on the first found
10431053
break
10441054
else:
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""Tests for no-member for self-referencing instance attributes
2+
See https://github.com/PyCQA/pylint/issues/1555
3+
"""
4+
# pylint: disable=too-few-public-methods
5+
6+
7+
class ClassWithMember:
8+
"""Member defined in superclass."""
9+
def __init__(self):
10+
self.member = True
11+
12+
13+
class AssignMemberInSameLine:
14+
"""This class attempts to assign and access a member in the same line."""
15+
def __init__(self):
16+
self.member = self.member # [no-member]
17+
18+
19+
class AssignMemberInSameLineAfterTypeAnnotation:
20+
"""This might emit a message like `maybe-no-member` in the future."""
21+
def __init__(self):
22+
self.member: bool
23+
self.member = self.member
24+
25+
26+
class AssignMemberFromSuper1(ClassWithMember):
27+
"""This assignment is valid due to inheritance."""
28+
def __init__(self):
29+
self.member = self.member
30+
super().__init__()
31+
32+
33+
class AssignMemberFromSuper2(ClassWithMember):
34+
"""This assignment is valid due to inheritance."""
35+
def __init__(self):
36+
super().__init__()
37+
self.member = self.member
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
no-member:16:22:16:33:AssignMemberInSameLine.__init__:Instance of 'AssignMemberInSameLine' has no 'member' member:INFERENCE

0 commit comments

Comments
 (0)