From c1038694faecad2ac79059688ac166aac0704f86 Mon Sep 17 00:00:00 2001 From: Mark Byrne Date: Thu, 1 Sep 2022 12:07:29 +0200 Subject: [PATCH] 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 --- doc/.DS_Store | Bin 0 -> 6148 bytes doc/whatsnew/fragments/6592.false_positive | 3 +++ pylint/checkers/typecheck.py | 13 +++++++++++++ tests/functional/a/arguments.py | 19 ++++++++++++++++++- 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 doc/.DS_Store create mode 100644 doc/whatsnew/fragments/6592.false_positive diff --git a/doc/.DS_Store b/doc/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f940bed6e384f5f76cd23313e2f8236eb972bc2c GIT binary patch literal 6148 zcmeHKI|>3Z5S>vG!N$@uSMUZw^aLJ2(QSkU3$fqIb9pr1d;e&iX;6Vd)od{|=!lohtBGA;&_%QP(7ai*Ls7pS=NC^Gt$`e=02O#vU>M7p)&Dj8 zP5=K);))7Tfxl8fN2|?hi6>=k?LE$FZGrFLmUDxfVeS+RUXFoYjlb| WP3!`lj=0l-{24G^XjI_a3fut+K^1ra literal 0 HcmV?d00001 diff --git a/doc/whatsnew/fragments/6592.false_positive b/doc/whatsnew/fragments/6592.false_positive new file mode 100644 index 00000000000..846ddce9611 --- /dev/null +++ b/doc/whatsnew/fragments/6592.false_positive @@ -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 diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index f9a55550412..c22d5cbfe51 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -1450,6 +1450,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) diff --git a/tests/functional/a/arguments.py b/tests/functional/a/arguments.py index a065e517e00..6929b985000 100644 --- a/tests/functional/a/arguments.py +++ b/tests/functional/a/arguments.py @@ -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""" @@ -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()