diff options
author | tiagohonorato <61059243+tiagohonorato@users.noreply.github.com> | 2021-03-21 16:29:31 -0300 |
---|---|---|
committer | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2021-03-28 22:48:56 +0200 |
commit | 812b681ee931bc34fb6e553713c651334d3f34a7 (patch) | |
tree | 5883e780f28e9483d488a8f513dc445fa34ed983 | |
parent | 005e0c73d5b71f98254130b46f453c91590a22c4 (diff) | |
download | pylint-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-- | ChangeLog | 3 | ||||
-rw-r--r-- | pylint/checkers/classes.py | 2 | ||||
-rw-r--r-- | tests/checkers/unittest_classes.py | 30 |
3 files changed, 35 insertions, 0 deletions
@@ -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) |