Skip to content

Commit

Permalink
Fixed false positives for function stubs
Browse files Browse the repository at this point in the history
Close #1581
  • Loading branch information
AWhetter committed May 21, 2019
1 parent b38a7c8 commit d8a5b11
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 1 deletion.
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ Release date: TBA

Close #202

* Fixed `unused-argument` and `function-redefined` getting raised for
functions decorated with `typing.overload`.

Close #1581

What's New in Pylint 2.3.0?
===========================

Expand Down
10 changes: 9 additions & 1 deletion pylint/checkers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,12 @@ def _check_in_loop(self, node, node_name):
def _check_redefinition(self, redeftype, node):
"""check for redefinition of a function / method / class name"""
parent_frame = node.parent.frame()
defined_self = parent_frame[node.name]
# Ignore function stubs created for type information
defined_self = next(
local
for local in parent_frame.locals[node.name]
if not utils.is_overload_stub(local)
)
if defined_self is not node and not astroid.are_exclusive(node, defined_self):

# Additional checks for methods which are not considered
Expand All @@ -847,6 +852,9 @@ def _check_redefinition(self, redeftype, node):
):
return

if utils.is_overload_stub(node):
return

dummy_variables_rgx = lint_utils.get_global_option(
self, "dummy-variables-rgx", default=None
)
Expand Down
12 changes: 12 additions & 0 deletions pylint/checkers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1210,3 +1210,15 @@ def is_subclass_of(child: astroid.ClassDef, parent: astroid.ClassDef) -> bool:
except _NonDeducibleTypeHierarchy:
continue
return False


@lru_cache(maxsize=1024)
def is_overload_stub(node: astroid.node_classes.NodeNG) -> bool:
"""Check if a node if is a function stub decorated with typing.overload.
:param node: Node to check.
:returns: True if node is an overload function stub. False otherwise.
"""
return isinstance(node, astroid.FunctionDef) and decorated_with(
node, ["typing.overload"]
)
10 changes: 10 additions & 0 deletions pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,11 @@ def _check_is_unused(self, name, node, stmt, global_names, nonlocal_names):
# Don't check arguments of singledispatch.register function.
if utils.is_registered_in_singledispatch_function(node):
return

# Don't check function stubs created only for type information
if utils.decorated_with(node, "typing.overload"):
return

self.add_message(
"unused-argument", args=name, node=stmt, confidence=confidence
)
Expand Down Expand Up @@ -1063,6 +1068,11 @@ def _check_is_unused(self, name, node, stmt, global_names, nonlocal_names):
self.add_message("unused-import", args=msg, node=stmt)
return
message_name = "unused-variable"

# Don't check function stubs created only for type information
if utils.is_overload_stub(node):
return

self.add_message(message_name, args=name, node=stmt)

def leave_functiondef(self, node):
Expand Down
51 changes: 51 additions & 0 deletions pylint/test/functional/typing_use.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# pylint: disable=missing-docstring

import typing


@typing.overload
def double_with_docstring(arg: str) -> str:
"""Return arg, concatenated with itself."""


@typing.overload
def double_with_docstring(arg: int) -> int:
"""Return twice arg."""


def double_with_docstring(arg):
"""Return 2 * arg."""
return 2 * arg


def double_with_docstring(arg): # [function-redefined]
"""Redefined function implementation"""
return 2 * arg


@typing.overload
def double_with_ellipsis(arg: str) -> str:
...


@typing.overload
def double_with_ellipsis(arg: int) -> int:
...


def double_with_ellipsis(arg):
return 2 * arg


@typing.overload
def double_with_pass(arg: str) -> str:
pass


@typing.overload
def double_with_pass(arg: int) -> int:
pass


def double_with_pass(arg):
return 2 * arg
2 changes: 2 additions & 0 deletions pylint/test/functional/typing_use.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[testoptions]
min_pyver=3.6
1 change: 1 addition & 0 deletions pylint/test/functional/typing_use.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
function-redefined:21:double_with_docstring:"function already defined line 16"

0 comments on commit d8a5b11

Please sign in to comment.