Skip to content

Commit

Permalink
Fix false positive protected-access in typing (pylint-dev#4937)
Browse files Browse the repository at this point in the history
* Fix false positive ``protected-access`` in typing
Class functions can return protected members which can then be passed
as arguments to other functions.
When using type hints in function definitions these raised a message
which they shouldn't do.
  • Loading branch information
DanielNoord committed Aug 31, 2021
1 parent 8b778cd commit e1da3c0
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 7 deletions.
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Release date: TBA

Closes #4936

* Fix false positive for ``protected-access`` if a protected member is used in type hints of function definitions


What's New in Pylint 2.10.3?
============================
Expand Down
3 changes: 0 additions & 3 deletions doc/whatsnew/2.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ Other Changes

* ``consider-using-with`` is no longer triggered if a context manager is returned from a function.

* Fix false positive for ``consider-using-with`` if a context manager is assigned to a
variable in different paths of control flow (e. g. if-else clause).

* pylint does not crash with a traceback anymore when a file is problematic. It
creates a template text file for opening an issue on the bug tracker instead.
The linting can go on for other non problematic files instead of being impossible.
Expand Down
10 changes: 8 additions & 2 deletions doc/whatsnew/2.11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@ New checkers
Extensions
==========


* Added new extension ``SetMembershipChecker`` with ``use-set-for-membership`` check:
Emitted when using an in-place defined ``list`` or ``tuple`` to do a membership test. ``sets`` are better optimized for that.

Closes #4776


* ``CodeStyleChecker``

* Added ``consider-using-assignment-expr``: Emitted when an assignment is directly followed by an if statement
Expand All @@ -40,8 +38,16 @@ Other Changes

* Added ``py-version`` config key (if ``[MASTER]`` section). Used for version dependant checks.
Will default to whatever Python version pylint is executed with.

* The ``invalid-name`` message is now more detailed when using multiple naming style regexes.

* Fix false positive for ``consider-using-with`` if a context manager is assigned to a
variable in different paths of control flow (e. g. if-else clause).

Closes #4751

* Fix false positive for ``function-redefined`` for simple type annotations

Closes #4936

* Fix false positive for ``protected-access`` if a protected member is used in type hints of function definitions
8 changes: 6 additions & 2 deletions pylint/checkers/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
import astroid
from astroid import nodes

from pylint.checkers import BaseChecker
from pylint.checkers import BaseChecker, utils
from pylint.checkers.utils import (
PYMETHODS,
SPECIAL_METHODS_PARAMS,
Expand Down Expand Up @@ -1563,7 +1563,7 @@ def _check_classmethod_declaration(self, node):
if any(method_name == member.name for member in parent_class.mymethods()):
self.add_message(msg, node=node.targets[0])

def _check_protected_attribute_access(self, node):
def _check_protected_attribute_access(self, node: nodes.Attribute):
"""Given an attribute access node (set or get), check if attribute
access is legitimate. Call _check_first_attr with node before calling
this method. Valid cases are:
Expand All @@ -1586,6 +1586,10 @@ def _check_protected_attribute_access(self, node):
# through the class object or through super
callee = node.expr.as_string()

# Typing annotations in funciton definitions can include protected members
if utils.is_node_in_type_annotation_context(node):
return

# We are not in a class, no remaining valid case
if klass is None:
self.add_message("protected-access", node=node, args=attrname)
Expand Down
32 changes: 32 additions & 0 deletions tests/functional/a/access/access_to_protected_members_typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# pylint: disable=too-few-public-methods, invalid-name
"""Test typing with a protected member"""
from __future__ import annotations


class MyClass:
"""Class with protected members."""

class _Inner_Class:
"""Inner class with protected members."""

def __init__(self) -> None:
self.data = 1

def return_data(self) -> int:
"""Return data"""
return self.data

def return_private_class(self) -> MyClass._Inner_Class:
"""Doing nothing."""
return self._Inner_Class()


def access_protected_class(data: MyClass._Inner_Class) -> int:
"""Function that always receives a protected class."""
return data.return_data() + 1


def pass_protected_class() -> None:
"""Function that passes a protected class to another function."""
data_value = access_protected_class(MyClass().return_private_class())
print(data_value)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[testoptions]
min_pyver=3.7
Empty file.

0 comments on commit e1da3c0

Please sign in to comment.