pylint
pylint copied to clipboard
arguments-differ: number of parameters was some number ... and is now the same number in overridden ...
Bug description
The following code produces a warning that does not really tell much about what is going wrong:
"""Comment."""
class Base:
"""Comment."""
def fun(self, var: int) -> int:
"""Comment."""
print(var)
class Class(Base):
"""Comment."""
def fun(self, *, var: int) -> int:
print(var)
Configuration
No response
Command used
pylint bug.py
Pylint output
************* Module bug
bug.py:15:4: W0221: Number of parameters was 2 in 'Base.fun' and is now 2 in overridden 'Class.fun' method (arguments-differ)
------------------------------------------------------------------
Your code has been rated at 8.33/10 (previous run: 8.33/10, +0.00)
Expected behavior
I'd expect a more meaningful warning not only referring to the number parameters (which has not changed from Base.fun
to Class.fun
).
Pylint version
pylint 2.12.2
astroid 2.9.3
Python 3.10.2 (main, Jan 17 2022, 14:26:36) [GCC 7.5.0]
OS / Environment
No response
Additional dependencies
No response
This also happens with following code:
class Base():
"""Base class"""
def test_method(self, param1, param2, /):
"""Method with positional-only arguments"""
return param1 + param2
class SubClass(Base):
"""Subclassing Base"""
def test_method(self, param1, param2):
"""Overwriting method withtout /"""
return param1 - param2
Same issue when overriting method of class which's metaclass=ABCMeta even if they totally same
Also stumbled across this in some code. I don't think it's a false positive hit, just confusing (though you can make a very contrived false positive if your method parameter signature is ...(self, /, params)
As far as a fix, when introspecting the code, the error should probably compare a tuple of (positional_only, named_positional, keyword_only)
, and maybe in the most common case if it's (0, x, 0), print the same error as before, but if there are any of the more bespoke arg types, get a bit more verbose?
def fun(self, *, var: int) -> int:
print(var)
Number of parameters was 2 in 'Base.fun' and is now 1 with 1 keyword-only parameter in ...
def fun(self, var: int, /) -> int:
print(var)
Number of parameters was 2 in 'Base.fun' and is now 0 with 2 position-only parameters in ...
The number of error string permutations with the 1, 2, 3 param types vs. 1, 2, 3 seems like a nightmare though...maybe just punt and say Number and/or types of parameters...
differ :upside_down_face:
One additional complication: self
and cls
should be considered implicitly positional-only if no positional-only marker is included. Otherwise, it becomes impossible to add optional positional-only arguments when overriding a function that previously had no positional-only arguments:
class Base:
def func(self):
pass
@classmethod
def class_func(cls):
pass
class Child(Base):
def func(self, arg=None, /):
pass
@classmethod
def class_func(cls, arg=None, /):
pass
Currently, you get a warning "Number of parameters was 1 in 'Base.func' and is now 0 in overriding 'Child.func' method (arguments-differ)". However, this is actually a perfectly valid override, since self
is never specified positionally or as a keyword; it is set when accessing the method of the object.