Skip to content

Commit

Permalink
Fix private method hidden by ancestor class attribute (pylint-dev#4177)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
tiagohonorato and Pierre-Sassoulas committed Mar 21, 2021
1 parent 02a3a92 commit 394060e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,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``
Expand Down
2 changes: 2 additions & 0 deletions pylint/checkers/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,8 @@ def visit_functiondef(self, node):

# 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
Expand Down
30 changes: 30 additions & 0 deletions tests/checkers/unittest_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,33 @@ def _fake_special_(self, other):
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)

0 comments on commit 394060e

Please sign in to comment.