pylint icon indicating copy to clipboard operation
pylint copied to clipboard

arguments-differ: number of parameters was some number ... and is now the same number in overridden ...

Open bersbersbers opened this issue 2 years ago • 3 comments

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

bersbersbers avatar Feb 11 '22 07:02 bersbersbers

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

Aguileitus avatar Jun 06 '22 04:06 Aguileitus

Same issue when overriting method of class which's metaclass=ABCMeta even if they totally same

saddit avatar Jun 07 '22 07:06 saddit

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:

nicktimko avatar Jul 19 '22 02:07 nicktimko

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.

macdjord avatar Nov 25 '23 01:11 macdjord