Skip to content

Commit 52cf631

Browse files
[invalid-class-object] Fix crash when __class__ is defined with a tuple
Closes #7467
1 parent 8e05ff6 commit 52cf631

File tree

4 files changed

+63
-3
lines changed

4 files changed

+63
-3
lines changed

doc/whatsnew/fragments/7467.bugfix

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
``invalid-class-object`` does not crash anymore when ``__class__`` is assigned alongside another variable.
2+
3+
Closes #7467

pylint/checkers/classes/class_checker.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -1558,7 +1558,18 @@ def visit_assignattr(self, node: nodes.AssignAttr) -> None:
15581558
def _check_invalid_class_object(self, node: nodes.AssignAttr) -> None:
15591559
if not node.attrname == "__class__":
15601560
return
1561-
inferred = safe_infer(node.parent.value)
1561+
if isinstance(node.parent, nodes.Tuple):
1562+
class_index = -1
1563+
for i, elt in enumerate(node.parent.elts):
1564+
if hasattr(elt, "attrname") and elt.attrname == "__class__":
1565+
class_index = i
1566+
if class_index == -1:
1567+
# This should not happen because we checked that the node name
1568+
# is '__class__' earlier, but let's not be too confident here
1569+
return # pragma: no cover
1570+
inferred = safe_infer(node.parent.parent.value.elts[class_index])
1571+
else:
1572+
inferred = safe_infer(node.parent.value)
15621573
if (
15631574
isinstance(inferred, nodes.ClassDef)
15641575
or inferred is astroid.Uninferable

tests/functional/i/invalid/invalid_class_object.py

+43
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
# pylint: disable=missing-docstring,too-few-public-methods,invalid-name
22
from collections import defaultdict
33

4+
45
class A:
56
pass
67

8+
79
class B:
810
pass
911

12+
1013
A.__class__ = B
1114
A.__class__ = str
1215
A.__class__ = float
@@ -30,3 +33,43 @@ def __deepcopy__(self, memo):
3033
obj = C()
3134
obj.__class__ = self.__class__
3235
return obj
36+
37+
38+
class AnotherClass:
39+
...
40+
41+
42+
class Pylint7429Good:
43+
"""See https://github.com/PyCQA/pylint/issues/7467"""
44+
45+
def class_defining_function_good(self):
46+
self.__class__, myvar = AnotherClass, "myvalue"
47+
print(myvar)
48+
49+
def class_defining_function_bad(self):
50+
self.__class__, myvar = 1, "myvalue" # [invalid-class-object]
51+
print(myvar)
52+
53+
def class_defining_function_good_inverted(self):
54+
myvar, self.__class__ = "myvalue", AnotherClass
55+
print(myvar)
56+
57+
def class_defining_function_bad_inverted(self):
58+
myvar, self.__class__ = "myvalue", 1 # [invalid-class-object]
59+
print(myvar)
60+
61+
def class_defining_function_complex_bad(self):
62+
myvar, self.__class__, other = ( # [invalid-class-object]
63+
"myvalue",
64+
1,
65+
"othervalue",
66+
)
67+
print(myvar, other)
68+
69+
def class_defining_function_complex_good(self):
70+
myvar, self.__class__, other = (
71+
"myvalue",
72+
str,
73+
"othervalue",
74+
)
75+
print(myvar, other)
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1-
invalid-class-object:17:0:17:11::Invalid __class__ object:UNDEFINED
2-
invalid-class-object:18:0:18:11::Invalid __class__ object:UNDEFINED
1+
invalid-class-object:20:0:20:11::Invalid __class__ object:UNDEFINED
2+
invalid-class-object:21:0:21:11::Invalid __class__ object:UNDEFINED
3+
invalid-class-object:50:8:50:22:Pylint7429Good.class_defining_function_bad:Invalid __class__ object:UNDEFINED
4+
invalid-class-object:58:15:58:29:Pylint7429Good.class_defining_function_bad_inverted:Invalid __class__ object:UNDEFINED
5+
invalid-class-object:62:15:62:29:Pylint7429Good.class_defining_function_complex_bad:Invalid __class__ object:UNDEFINED

0 commit comments

Comments
 (0)