Skip to content

Commit

Permalink
Fix false positive for too-many-function-args when a function cal…
Browse files Browse the repository at this point in the history
…l is assigned to a class attribute inside the class where the function is defined.

Closes pylint-dev#6592
  • Loading branch information
mbyrnepr2 committed Sep 1, 2022
1 parent bcd4ca3 commit 1d54c38
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 1 deletion.
Binary file added doc/.DS_Store
Binary file not shown.
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/6592.false_positive
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix false positive for ``too-many-function-args`` when a function call is assigned to a class attribute inside the class where the function is defined.

Closes #6592
13 changes: 13 additions & 0 deletions pylint/checkers/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -1458,6 +1458,19 @@ def visit_call(self, node: nodes.Call) -> None:
keyword_args += list(already_filled_keywords)
num_positional_args += implicit_args + already_filled_positionals

# Decrement `num_positional_args` by 1 when a function call is assigned to a class attribute
# inside the class where the function is defined.
# This avoids emitting `too-many-function-args` since `num_positional_args`
# includes an implicit `self` argument which is not present in `called.args`.
if (
isinstance(node.frame(), nodes.ClassDef)
and isinstance(node.parent, (nodes.Assign, nodes.AnnAssign))
and isinstance(called, nodes.FunctionDef)
and called in node.frame().body
and num_positional_args > 0
):
num_positional_args -= 1

# Analyze the list of formal parameters.
args = list(itertools.chain(called.args.posonlyargs or (), called.args.args))
num_mandatory_parameters = len(args) - len(called.args.defaults)
Expand Down
19 changes: 18 additions & 1 deletion tests/functional/a/arguments.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pylint: disable=too-few-public-methods, missing-docstring,import-error,wrong-import-position
# pylint: disable=wrong-import-order, unnecessary-lambda, consider-using-f-string
# pylint: disable=unnecessary-lambda-assignment
# pylint: disable=unnecessary-lambda-assignment, no-self-argument, unused-argument

def decorator(fun):
"""Decorator"""
Expand Down Expand Up @@ -261,3 +261,20 @@ def func(one, two, three):


CALL = lambda *args: func(*args)


# Ensure `too-many-function-args` is not emitted when a function call is assigned
# to a class attribute inside the class where the function is defined.
# Reference: https://github.com/PyCQA/pylint/issues/6592
class FruitPicker:
def _pick_fruit(fruit):
def _print_selection(self):
print(f"Selected: {fruit}!")
return _print_selection

pick_apple = _pick_fruit("apple")
pick_pear = _pick_fruit("pear")

picker = FruitPicker()
picker.pick_apple()
picker.pick_pear()

0 comments on commit 1d54c38

Please sign in to comment.