summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortiagohonorato <61059243+tiagohonorato@users.noreply.github.com>2021-03-21 16:29:31 -0300
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2021-03-28 22:48:56 +0200
commit812b681ee931bc34fb6e553713c651334d3f34a7 (patch)
tree5883e780f28e9483d488a8f513dc445fa34ed983
parent005e0c73d5b71f98254130b46f453c91590a22c4 (diff)
downloadpylint-git-812b681ee931bc34fb6e553713c651334d3f34a7.tar.gz
Fix private method hidden by ancestor class attribute (#4177)
* Fix private method hidden by ancestor class attribute A class defined private method won't be hidden by an ancestor class private attribute as the class will mangle the latter to avoid naming collisions. Add tests to assert method-hidden : Although private attributes from the parent class should not hide methods in the child class, this is not true for protected attributes. This test ensures that ``method-hidden`` catches the error when private attributes are not in use. Signed-off-by: Tiago Honorato <tiagohonorato1@gmail.com> Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
-rw-r--r--ChangeLog3
-rw-r--r--pylint/checkers/classes.py2
-rw-r--r--tests/checkers/unittest_classes.py30
3 files changed, 35 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index a23865228..9174c31a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,9 @@ Release date: TBA
..
Put bug fixes that will be cherry-picked to latest major version here
+* Fix false positive for ``method-hidden`` when using private attribute and method
+
+ Closes #3936
* ``use-symbolic-message-instead`` now also works on legacy messages like ``C0111`` (``missing-docstring``).
* Remove unwanted print to stdout from ``_emit_no_member``
diff --git a/pylint/checkers/classes.py b/pylint/checkers/classes.py
index d475cfcfb..c96cce007 100644
--- a/pylint/checkers/classes.py
+++ b/pylint/checkers/classes.py
@@ -1000,6 +1000,8 @@ a metaclass class method.",
# If a subclass defined the method then it's not our fault.
for ancestor in klass.ancestors():
+ if node.name in ancestor.instance_attrs and is_attr_private(node.name):
+ return
for obj in ancestor.lookup(node.name)[1]:
if isinstance(obj, astroid.FunctionDef):
return
diff --git a/tests/checkers/unittest_classes.py b/tests/checkers/unittest_classes.py
index ecbc72c4a..4cf0a6cb1 100644
--- a/tests/checkers/unittest_classes.py
+++ b/tests/checkers/unittest_classes.py
@@ -187,3 +187,33 @@ class TestVariablesChecker(CheckerTestCase):
Message("protected-access", node=attribute_in_fake_2, args="__private"),
):
self.walk(node.root())
+
+ def test_private_attribute_hides_method(self):
+ node = astroid.extract_node(
+ """
+ class Parent:
+ def __init__(self):
+ self.__private = None
+
+ class Child(Parent):
+ def __private(self): #@
+ pass
+ """
+ )
+ with self.assertNoMessages():
+ self.checker.visit_functiondef(node)
+
+ def test_protected_attribute_hides_method(self):
+ node = astroid.extract_node(
+ """
+ class Parent:
+ def __init__(self):
+ self._protected = None
+
+ class Child(Parent):
+ def _protected(self): #@
+ pass
+ """
+ )
+ with self.assertAddsMessages(Message("method-hidden", node=node, args=("", 4))):
+ self.checker.visit_functiondef(node)