Skip to content

Fix false positive for invalid-class-object when inference fails #5901

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

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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ Release date: TBA

Closes #3793

* Fixed a false positive for ``invalid-class-object`` when the object
being assigned to the ``__class__`` attribute is uninferable.

* Fixed false positive for ``used-before-assignment`` with self-referential type
annotation in conditional statements within class methods.

Expand Down
3 changes: 3 additions & 0 deletions doc/whatsnew/2.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,9 @@ Other Changes

Closes #3793

* Fixed a false positive for ``invalid-class-object`` when the object
being assigned to the ``__class__`` attribute is uninferable.

* Added a ``testutil`` extra require to the packaging, as ``gitpython`` should not be a dependency
all the time but is still required to use the primer helper code in ``pylint.testutil``. You can
install it with ``pip install pylint[testutil]``.
Expand Down
8 changes: 6 additions & 2 deletions pylint/checkers/classes/class_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1482,8 +1482,12 @@ def _check_invalid_class_object(self, node: nodes.AssignAttr) -> None:
if not node.attrname == "__class__":
return
inferred = safe_infer(node.parent.value)
if isinstance(inferred, nodes.ClassDef) or inferred is astroid.Uninferable:
# If is uninferrable, we allow it to prevent false positives
if (
isinstance(inferred, nodes.ClassDef)
or inferred is astroid.Uninferable
or inferred is None
):
# If is uninferable, we allow it to prevent false positives
return
self.add_message("invalid-class-object", node=node)

Expand Down
14 changes: 14 additions & 0 deletions tests/functional/i/invalid/invalid_class_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,17 @@ class B:
A.__class__ = defaultdict
A.__class__ = defaultdict(str) # [invalid-class-object]
A.__class__ = 1 # [invalid-class-object]


# Here, ambiguity is found when inferring self.__class__
class C:
@classmethod
def _new_instance(cls):
obj = C()
obj.__class__ = cls
return obj

def __deepcopy__(self, memo):
obj = C()
obj.__class__ = self.__class__
return obj