Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/whatsnew/fragments/8675.false_positive
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix a false positive for ``too-many-arguments`` in (non-static) methods and classmethods.

Closes #8675
27 changes: 13 additions & 14 deletions pylint/checkers/design_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,11 +542,13 @@ def visit_functiondef(self, node: nodes.FunctionDef) -> None:
# init branch and returns counters
self._returns.append(0)
# check number of arguments
args = node.args.args + node.args.posonlyargs + node.args.kwonlyargs
pos_args = node.args.args + node.args.posonlyargs
pos_args = node.args.posonlyargs + node.args.args
Comment thread
jacobtylerwalls marked this conversation as resolved.
if node.type in {"method", "classmethod"}:
pos_args = pos_args[1:]
args = pos_args + node.args.kwonlyargs
ignored_argument_names = self.linter.config.ignored_argument_names
if args is not None:
ignored_args_num = 0
ignored_args_num = 0
if args:
if ignored_argument_names:
ignored_pos_args_num = sum(
1 for arg in pos_args if ignored_argument_names.match(arg.name)
Expand All @@ -558,25 +560,22 @@ def visit_functiondef(self, node: nodes.FunctionDef) -> None:
)
ignored_args_num = ignored_pos_args_num + ignored_kwonly_args_num

argnum = len(args) - ignored_args_num
if argnum > self.linter.config.max_args:
args_num = len(args) - ignored_args_num
if args_num > self.linter.config.max_args:
self.add_message(
"too-many-arguments",
node=node,
args=(len(args), self.linter.config.max_args),
args=(args_num, self.linter.config.max_args),
)
pos_args_count = (
len(args) - len(node.args.kwonlyargs) - ignored_pos_args_num
)
if pos_args_count > self.linter.config.max_positional_arguments:
pos_args_num = len(pos_args) - ignored_pos_args_num
if pos_args_num > self.linter.config.max_positional_arguments:
self.add_message(
"too-many-positional-arguments",
node=node,
args=(pos_args_count, self.linter.config.max_positional_arguments),
args=(pos_args_num, self.linter.config.max_positional_arguments),
confidence=HIGH,
)
else:
ignored_args_num = 0

# check number of local variables
locnum = len(node.locals) - ignored_args_num

Expand Down
4 changes: 0 additions & 4 deletions pylint/config/argument.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,6 @@ class _StoreArgument(_BaseStoreArgument):
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument
"""

# pylint: disable-next=too-many-arguments
def __init__(
self,
*,
Expand Down Expand Up @@ -307,7 +306,6 @@ class _DeprecationArgument(_Argument):
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument
"""

# pylint: disable-next=too-many-arguments
def __init__(
self,
*,
Expand Down Expand Up @@ -397,7 +395,6 @@ class _StoreOldNamesArgument(_DeprecationArgument):
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument
"""

# pylint: disable-next=too-many-arguments
def __init__(
self,
*,
Expand Down Expand Up @@ -435,7 +432,6 @@ class _StoreNewNamesArgument(_DeprecationArgument):
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_argument
"""

# pylint: disable-next=too-many-arguments
def __init__(
self,
*,
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/a/async_functions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ redefined-builtin:5:0:5:14:next:Redefining built-in 'next':UNDEFINED
unused-argument:8:30:8:34:some_function:Unused argument 'arg2':HIGH
bad-super-call:22:8:22:31:Class.some_method:Bad first argument 'OtherClass' given to super():UNDEFINED
line-too-long:26:0:None:None::Line too long (104/100):UNDEFINED
too-many-arguments:27:0:27:26:complex_function:Too many arguments (10/5):UNDEFINED
too-many-arguments:27:0:27:26:complex_function:Too many arguments (9/5):UNDEFINED
too-many-branches:27:0:27:26:complex_function:Too many branches (13/12):UNDEFINED
too-many-positional-arguments:27:0:27:26:complex_function:Too many positional arguments (9/5):HIGH
too-many-return-statements:27:0:27:26:complex_function:Too many return statements (10/6):UNDEFINED
Expand Down
143 changes: 138 additions & 5 deletions tests/functional/t/too/too_many_positional_arguments.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,142 @@
# pylint: disable=missing-function-docstring, missing-module-docstring
class FiveArgumentMethods:
"""The max positional arguments default is 5."""
def fail1(self, a, b, c, d, e): # [too-many-arguments, too-many-positional-arguments]
class RegularMethods:
"""The max positional arguments default is 5. Regular methods don't count `self`."""

# +1: [too-many-arguments, too-many-positional-arguments]
def regular_fail1(self, a, b, c, d, e, f):
pass
def fail2(self, a, b, c, d, /, e): # [too-many-arguments, too-many-positional-arguments]
# +1: [too-many-arguments, too-many-positional-arguments]
def regular_fail2(self, a, b, c, d, e, /, f):
pass
def okay1(self, a, b, c, d, *, e=True): # [too-many-arguments]
# +1: [too-many-arguments, too-many-positional-arguments]
def regular_fail3(self, /, a, b, c, d, e, f):
pass
# +1: [too-many-arguments]
def regular_soso1(self, a, b, c, d, e, *, f=True):
pass
# +1: [too-many-arguments]
def regular_soso2(self, a, b, c, d, e, /, *, f=True):
pass
# +1: [too-many-arguments]
def regular_soso3(self, /, a, b, c, d, e, *, f=True):
pass
# +1: [too-many-arguments]
def regular_soso4(self, a, b, c, d, e, /, _f, *, g=True):
pass
# +1: [too-many-arguments]
def regular_soso5(self, /, _a, b, c, d, e, f, *, g=True):
pass
def regular_okay1(self, a, b, c, d, e):
pass
def regular_okay2(self, a, b, c, d, e, /):
pass
def regular_okay3(self, *, a, b, c, d, e):
pass
def regular_okay4(self, a, b, c, d, e, /, _f):
pass
def regular_okay5(self, _a, b, c, d, e, /, f):
pass
def regular_okay6(self, /, _a, b, c, d, e, f):
pass
def regular_okay7(self, /, a, b, c, d, e, _f):
pass


# pylint: disable=missing-function-docstring, missing-module-docstring
class StaticMethods:
"""The max positional arguments default is 5. Static methods count them all."""

@staticmethod
# +1: [too-many-arguments, too-many-positional-arguments]
def static_fail1(a, b, c, d, e, f):
pass
@staticmethod
# +1: [too-many-arguments, too-many-positional-arguments]
def static_fail2(a, b, c, d, e, /, f):
pass
@staticmethod
# +1: [too-many-arguments]
def static_soso1(a, b, c, d, e, *, f=True):
pass
@staticmethod
# +1: [too-many-arguments]
def static_soso2(a, b, c, d, e, /, *, f=True):
pass
@staticmethod
# +1: [too-many-arguments]
def static_soso3(a, b, c, d, e, /, _f, *, g=True):
pass
@staticmethod
def static_okay1(a, b, c, d, e):
pass
@staticmethod
def static_okay2(a, b, c, d, e, /):
pass
@staticmethod
def static_okay3(*, a, b, c, d, e):
pass
@staticmethod
def static_okay4(a, b, c, d, e, /, _f):
pass
@staticmethod
def static_okay5(_a, b, c, d, e, /, f):
pass


# pylint: disable=missing-function-docstring, missing-module-docstring
class ClassMethods:
"""The max positional arguments default is 5. Class methods don't count `cls`."""

@classmethod
# +1: [too-many-arguments, too-many-positional-arguments]
def class_fail1(cls, a, b, c, d, e, f):
pass
@classmethod
# +1: [too-many-arguments, too-many-positional-arguments]
def class_fail2(cls, a, b, c, d, e, /, f):
pass
@classmethod
# +1: [too-many-arguments, too-many-positional-arguments]
def class_fail3(cls, /, a, b, c, d, e, f):
pass
@classmethod
# +1: [too-many-arguments]
def class_soso1(cls, a, b, c, d, e, *, f=True):
pass
@classmethod
# +1: [too-many-arguments]
def class_soso2(cls, a, b, c, d, e, /, *, f=True):
pass
@classmethod
# +1: [too-many-arguments]
def class_soso3(cls, /, a, b, c, d, e, *, f=True):
pass
@classmethod
# +1: [too-many-arguments]
def class_soso4(cls, a, b, c, d, e, /, _f, *, g=True):
pass
@classmethod
# +1: [too-many-arguments]
def class_soso5(cls, /, _a, b, c, d, e, f, *, g=True):
pass
@classmethod
def class_okay1(cls, a, b, c, d, e):
pass
@classmethod
def class_okay2(cls, a, b, c, d, e, /):
pass
@classmethod
def class_okay3(cls, *, a, b, c, d, e):
pass
@classmethod
def class_okay4(cls, a, b, c, d, e, /, _f):
pass
@classmethod
def class_okay5(cls, _a, b, c, d, e, /, f):
pass
@classmethod
def class_okay6(cls, /, _a, b, c, d, e, f):
pass
@classmethod
def class_okay7(cls, /, a, b, c, d, e, _f):
pass
34 changes: 29 additions & 5 deletions tests/functional/t/too/too_many_positional_arguments.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
too-many-arguments:4:4:4:13:FiveArgumentMethods.fail1:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:4:4:4:13:FiveArgumentMethods.fail1:Too many positional arguments (6/5):HIGH
too-many-arguments:6:4:6:13:FiveArgumentMethods.fail2:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:6:4:6:13:FiveArgumentMethods.fail2:Too many positional arguments (6/5):HIGH
too-many-arguments:8:4:8:13:FiveArgumentMethods.okay1:Too many arguments (6/5):UNDEFINED
too-many-arguments:6:4:6:21:RegularMethods.regular_fail1:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:6:4:6:21:RegularMethods.regular_fail1:Too many positional arguments (6/5):HIGH
too-many-arguments:9:4:9:21:RegularMethods.regular_fail2:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:9:4:9:21:RegularMethods.regular_fail2:Too many positional arguments (6/5):HIGH
too-many-arguments:12:4:12:21:RegularMethods.regular_fail3:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:12:4:12:21:RegularMethods.regular_fail3:Too many positional arguments (6/5):HIGH
too-many-arguments:15:4:15:21:RegularMethods.regular_soso1:Too many arguments (6/5):UNDEFINED
too-many-arguments:18:4:18:21:RegularMethods.regular_soso2:Too many arguments (6/5):UNDEFINED
too-many-arguments:21:4:21:21:RegularMethods.regular_soso3:Too many arguments (6/5):UNDEFINED
too-many-arguments:24:4:24:21:RegularMethods.regular_soso4:Too many arguments (6/5):UNDEFINED
too-many-arguments:27:4:27:21:RegularMethods.regular_soso5:Too many arguments (6/5):UNDEFINED
too-many-arguments:51:4:51:20:StaticMethods.static_fail1:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:51:4:51:20:StaticMethods.static_fail1:Too many positional arguments (6/5):HIGH
too-many-arguments:55:4:55:20:StaticMethods.static_fail2:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:55:4:55:20:StaticMethods.static_fail2:Too many positional arguments (6/5):HIGH
too-many-arguments:59:4:59:20:StaticMethods.static_soso1:Too many arguments (6/5):UNDEFINED
too-many-arguments:63:4:63:20:StaticMethods.static_soso2:Too many arguments (6/5):UNDEFINED
too-many-arguments:67:4:67:20:StaticMethods.static_soso3:Too many arguments (6/5):UNDEFINED
too-many-arguments:92:4:92:19:ClassMethods.class_fail1:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:92:4:92:19:ClassMethods.class_fail1:Too many positional arguments (6/5):HIGH
too-many-arguments:96:4:96:19:ClassMethods.class_fail2:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:96:4:96:19:ClassMethods.class_fail2:Too many positional arguments (6/5):HIGH
too-many-arguments:100:4:100:19:ClassMethods.class_fail3:Too many arguments (6/5):UNDEFINED
too-many-positional-arguments:100:4:100:19:ClassMethods.class_fail3:Too many positional arguments (6/5):HIGH
too-many-arguments:104:4:104:19:ClassMethods.class_soso1:Too many arguments (6/5):UNDEFINED
too-many-arguments:108:4:108:19:ClassMethods.class_soso2:Too many arguments (6/5):UNDEFINED
too-many-arguments:112:4:112:19:ClassMethods.class_soso3:Too many arguments (6/5):UNDEFINED
too-many-arguments:116:4:116:19:ClassMethods.class_soso4:Too many arguments (6/5):UNDEFINED
too-many-arguments:120:4:120:19:ClassMethods.class_soso5:Too many arguments (6/5):UNDEFINED
Loading