summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Sassoulas <pierre.sassoulas@gmail.com>2022-09-16 10:20:43 +0200
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2022-09-19 16:19:58 +0200
commit52cf631d732f7b39a879adf7e617e0aa7059a83a (patch)
treec010fb3653d63b88c49a857f55eb32b8fc3ec2f8
parent8e05ff6acf30deae5d83ea3847ec47ed0bf049a4 (diff)
downloadpylint-git-52cf631d732f7b39a879adf7e617e0aa7059a83a.tar.gz
[invalid-class-object] Fix crash when __class__ is defined with a tuple
Closes #7467
-rw-r--r--doc/whatsnew/fragments/7467.bugfix3
-rw-r--r--pylint/checkers/classes/class_checker.py13
-rw-r--r--tests/functional/i/invalid/invalid_class_object.py43
-rw-r--r--tests/functional/i/invalid/invalid_class_object.txt7
4 files changed, 63 insertions, 3 deletions
diff --git a/doc/whatsnew/fragments/7467.bugfix b/doc/whatsnew/fragments/7467.bugfix
new file mode 100644
index 000000000..7e76f86a0
--- /dev/null
+++ b/doc/whatsnew/fragments/7467.bugfix
@@ -0,0 +1,3 @@
+``invalid-class-object`` does not crash anymore when ``__class__`` is assigned alongside another variable.
+
+Closes #7467
diff --git a/pylint/checkers/classes/class_checker.py b/pylint/checkers/classes/class_checker.py
index 5ae558822..059baa058 100644
--- a/pylint/checkers/classes/class_checker.py
+++ b/pylint/checkers/classes/class_checker.py
@@ -1558,7 +1558,18 @@ a metaclass class method.",
def _check_invalid_class_object(self, node: nodes.AssignAttr) -> None:
if not node.attrname == "__class__":
return
- inferred = safe_infer(node.parent.value)
+ if isinstance(node.parent, nodes.Tuple):
+ class_index = -1
+ for i, elt in enumerate(node.parent.elts):
+ if hasattr(elt, "attrname") and elt.attrname == "__class__":
+ class_index = i
+ if class_index == -1:
+ # This should not happen because we checked that the node name
+ # is '__class__' earlier, but let's not be too confident here
+ return # pragma: no cover
+ inferred = safe_infer(node.parent.parent.value.elts[class_index])
+ else:
+ inferred = safe_infer(node.parent.value)
if (
isinstance(inferred, nodes.ClassDef)
or inferred is astroid.Uninferable
diff --git a/tests/functional/i/invalid/invalid_class_object.py b/tests/functional/i/invalid/invalid_class_object.py
index 7c08ebae8..b7363e9c8 100644
--- a/tests/functional/i/invalid/invalid_class_object.py
+++ b/tests/functional/i/invalid/invalid_class_object.py
@@ -1,12 +1,15 @@
# pylint: disable=missing-docstring,too-few-public-methods,invalid-name
from collections import defaultdict
+
class A:
pass
+
class B:
pass
+
A.__class__ = B
A.__class__ = str
A.__class__ = float
@@ -30,3 +33,43 @@ class C:
obj = C()
obj.__class__ = self.__class__
return obj
+
+
+class AnotherClass:
+ ...
+
+
+class Pylint7429Good:
+ """See https://github.com/PyCQA/pylint/issues/7467"""
+
+ def class_defining_function_good(self):
+ self.__class__, myvar = AnotherClass, "myvalue"
+ print(myvar)
+
+ def class_defining_function_bad(self):
+ self.__class__, myvar = 1, "myvalue" # [invalid-class-object]
+ print(myvar)
+
+ def class_defining_function_good_inverted(self):
+ myvar, self.__class__ = "myvalue", AnotherClass
+ print(myvar)
+
+ def class_defining_function_bad_inverted(self):
+ myvar, self.__class__ = "myvalue", 1 # [invalid-class-object]
+ print(myvar)
+
+ def class_defining_function_complex_bad(self):
+ myvar, self.__class__, other = ( # [invalid-class-object]
+ "myvalue",
+ 1,
+ "othervalue",
+ )
+ print(myvar, other)
+
+ def class_defining_function_complex_good(self):
+ myvar, self.__class__, other = (
+ "myvalue",
+ str,
+ "othervalue",
+ )
+ print(myvar, other)
diff --git a/tests/functional/i/invalid/invalid_class_object.txt b/tests/functional/i/invalid/invalid_class_object.txt
index 221431b48..793a5de69 100644
--- a/tests/functional/i/invalid/invalid_class_object.txt
+++ b/tests/functional/i/invalid/invalid_class_object.txt
@@ -1,2 +1,5 @@
-invalid-class-object:17:0:17:11::Invalid __class__ object:UNDEFINED
-invalid-class-object:18:0:18:11::Invalid __class__ object:UNDEFINED
+invalid-class-object:20:0:20:11::Invalid __class__ object:UNDEFINED
+invalid-class-object:21:0:21:11::Invalid __class__ object:UNDEFINED
+invalid-class-object:50:8:50:22:Pylint7429Good.class_defining_function_bad:Invalid __class__ object:UNDEFINED
+invalid-class-object:58:15:58:29:Pylint7429Good.class_defining_function_bad_inverted:Invalid __class__ object:UNDEFINED
+invalid-class-object:62:15:62:29:Pylint7429Good.class_defining_function_complex_bad:Invalid __class__ object:UNDEFINED