From 76ac95ec22de0ab4dfa1727fc943465830754ecb Mon Sep 17 00:00:00 2001
From: "Yu Shao, Pang"
Date: Sat, 4 Sep 2021 23:50:57 +0800
Subject: [PATCH] Fix false positive ``unused-private-member`` for accessing
attributes in a class using ``cls``
---
ChangeLog | 4 ++++
doc/whatsnew/2.11.rst | 4 ++++
pylint/checkers/classes.py | 8 ++++----
.../u/unused/unused_private_member.py | 17 +++++++++++++++++
.../u/unused/unused_private_member.txt | 4 ++--
5 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index ee1b82af53..f173213930 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -63,6 +63,10 @@ Release date: TBA
Closes #4907
+* Fix false positive ``unused-private-member`` for accessing attributes in a class using ``cls``
+
+ Closes #4849
+
What's New in Pylint 2.10.3?
============================
diff --git a/doc/whatsnew/2.11.rst b/doc/whatsnew/2.11.rst
index cdbba865d4..c450abdf3c 100644
--- a/doc/whatsnew/2.11.rst
+++ b/doc/whatsnew/2.11.rst
@@ -69,3 +69,7 @@ Other Changes
* Fix false positive ``superfluous-parens`` for tuples created with inner tuples
Closes #4907
+
+* Fix false positive ``unused-private-member`` for accessing attributes in a class using ``cls``
+
+ Closes #4849
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index 59e4742204..eeef46c16d 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -1000,11 +1000,11 @@ def _check_unused_private_attributes(self, node: nodes.ClassDef) -> None:
if attribute.attrname != assign_attr.attrname:
continue
- if assign_attr.expr.name == "cls" and attribute.expr.name in [
+ if assign_attr.expr.name in [
"cls",
- "self",
- ]:
- # If assigned to cls.attrib, can be accessed by cls/self
+ node.name,
+ ] and attribute.expr.name in ["cls", "self", node.name]:
+ # If assigned to cls or class name, can be accessed by cls/self/class name
break
if (
diff --git a/tests/functional/u/unused/unused_private_member.py b/tests/functional/u/unused/unused_private_member.py
index 1acdd91249..93fdd1c746 100644
--- a/tests/functional/u/unused/unused_private_member.py
+++ b/tests/functional/u/unused/unused_private_member.py
@@ -242,6 +242,23 @@ def __init__(self):
FalsePositive4681.__instance = False # This should be fine
FalsePositive4681.__should_cause_error = False # [unused-private-member]
+# Accessing attributes of the class using `cls` should not result in a false positive
+# as long as it is used within the class
+class FalsePositive4681b:
+ __instance = None
+
+ @classmethod # Use class method here
+ def instance(cls):
+ if cls.__instance is None:
+ cls()
+ return cls.__instance
+
+ def __init__(self):
+ try:
+ FalsePositive4681b.__instance = 42 # This should be fine
+ except Exception: # pylint: disable=broad-except
+ print("Error")
+ FalsePositive4681b.__instance = False # This should be fine
class Pony:
"""https://github.com/PyCQA/pylint/issues/4837"""
diff --git a/tests/functional/u/unused/unused_private_member.txt b/tests/functional/u/unused/unused_private_member.txt
index 391316d354..4c6245be21 100644
--- a/tests/functional/u/unused/unused_private_member.txt
+++ b/tests/functional/u/unused/unused_private_member.txt
@@ -14,5 +14,5 @@ unused-private-member:212:8:Crash4755Context.__init__:Unused private member `Cra
unused-private-member:229:4:FalsePositive4681:Unused private member `FalsePositive4681.__should_cause_error`:HIGH
unused-private-member:239:12:FalsePositive4681.__init__:Unused private member `FalsePositive4681.__should_cause_error`:HIGH
unused-private-member:243:12:FalsePositive4681.__init__:Unused private member `FalsePositive4681.__should_cause_error`:HIGH
-unused-private-member:254:4:Pony.__init_defaults:Unused private member `Pony.__init_defaults(self)`:HIGH
-unused-private-member:259:4:Pony.__get_fur_color:Unused private member `Pony.__get_fur_color(self)`:HIGH
+unused-private-member:271:4:Pony.__init_defaults:Unused private member `Pony.__init_defaults(self)`:HIGH
+unused-private-member:276:4:Pony.__get_fur_color:Unused private member `Pony.__get_fur_color(self)`:HIGH