Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create new error arguments-renamed #4467

Merged
merged 11 commits into from
May 17, 2021
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ modules are added.

* Fix raising false-positive ``no-member`` on abstract properties

* Created new error message called ``arguments-renamed`` which identifies any changes at the parameter
names of overridden functions.

Closes #3536

* New checker ``consider-using-dict-items``. Emitted when iterating over dictionary keys and then
indexing the same dictionary with the key within loop body.

Expand Down
3 changes: 3 additions & 0 deletions doc/whatsnew/2.9.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ Other Changes

* New option ``--fail-on=<msg ids>`` to return non-zero exit codes regardless of ``fail-under`` value.

* A new error called ``arguments-renamed`` has been created, which identifies any changes at the parameter names
of overridden functions. It aims to separate the functionality of ``arguments-differ``.

* Fix incompatibility with Python 3.6.0 caused by ``typing.Counter`` and ``typing.NoReturn`` usage
19 changes: 19 additions & 0 deletions pylint/checkers/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,9 @@ def _different_parameters(
output_messages.append("Number of parameters ")
output_messages += different_positional[1:]
output_messages += different_kwonly[1:]
else:
output_messages += different_positional
output_messages += different_kwonly
else:
if different_positional:
output_messages += different_positional
Expand Down Expand Up @@ -627,6 +630,12 @@ def _has_same_layout_slots(slots, assigned_value):
"that does not match its base class "
"which could result in potential bugs at runtime.",
),
"W0237": (
"%s %s %r method",
"arguments-renamed",
"Used when a method parameter has a different name than in "
"the implemented interface or in an overridden method.",
),
"E0236": (
"Invalid object %r in __slots__, must contain only non empty strings",
"invalid-slots-object",
Expand Down Expand Up @@ -1821,6 +1830,16 @@ def _check_signature(self, method1, refmethod, class_type, cls):
),
node=method1,
)
elif "renamed" in msg:
self.add_message(
"arguments-renamed",
args=(
msg,
class_type,
str(method1.parent.name) + "." + str(method1.name),
),
node=method1,
)
else:
self.add_message(
"arguments-differ",
Expand Down
50 changes: 49 additions & 1 deletion tests/functional/a/arguments_differ.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class VarargsChild(Varargs):
def has_kwargs(self, arg): # [arguments-differ]
"Not okay to lose capabilities. Also, type has changed."

def no_kwargs(self, arg, **kwargs): # [arguments-differ]
def no_kwargs(self, arg, **kwargs): # [arguments-renamed]
"Addition of kwargs does not violate LSP, but first argument's name has changed."


Expand Down Expand Up @@ -270,3 +270,51 @@ def func(self, user_input: FooT1) -> None:
class ChildT3(ParentT3):
def func(self, user_input: FooT1) -> None:
pass

# Keyword and positional overriddes
class AbstractFoo:

def kwonly_1(self, first, *, second, third):
"Normal positional with two positional only params."

def kwonly_2(self, *, first, second):
"Two positional only parameter."

def kwonly_3(self, *, first, second):
"Two positional only params."

def kwonly_4(self, *, first, second=None):
"One positional only and another with a default."

def kwonly_5(self, *, first, **kwargs):
"Keyword only and keyword variadics."

def kwonly_6(self, first, second, *, third):
"Two positional and one keyword"


class Foo(AbstractFoo):

def kwonly_1(self, first, *, second): # [arguments-differ]
"One positional and only one positional only param."

def kwonly_2(self, *, first): # [arguments-differ]
"Only one positional parameter instead of two positional only parameters."

def kwonly_3(self, first, second): # [arguments-differ]
"Two positional params."

def kwonly_4(self, first, second): # [arguments-differ]
"Two positional params."

def kwonly_5(self, *, first): # [arguments-differ]
"Keyword only, but no variadics."

def kwonly_6(self, *args, **kwargs): # valid override
"Positional and keyword variadics to pass through parent params"


class Foo2(AbstractFoo):

def kwonly_6(self, first, *args, **kwargs): # valid override
"One positional with the rest variadics to pass through parent params"
7 changes: 6 additions & 1 deletion tests/functional/a/arguments_differ.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,10 @@ arguments-differ:12:4:Child.test:Number of parameters was 1 in 'Parent.test' and
arguments-differ:23:4:ChildDefaults.test:Number of parameters was 3 in 'ParentDefaults.test' and is now 2 in overridden 'ChildDefaults.test' method
arguments-differ:41:4:ClassmethodChild.func:Number of parameters was 2 in 'Classmethod.func' and is now 0 in overridden 'ClassmethodChild.func' method
arguments-differ:68:4:VarargsChild.has_kwargs:Variadics removed in overridden 'VarargsChild.has_kwargs' method
arguments-differ:71:4:VarargsChild.no_kwargs:Parameter 'args' has been renamed to 'arg' in overridden 'VarargsChild.no_kwargs' method
arguments-renamed:71:4:VarargsChild.no_kwargs:Parameter 'args' has been renamed to 'arg' in overridden 'VarargsChild.no_kwargs' method
arguments-differ:172:4:SecondChangesArgs.test:Number of parameters was 2 in 'FirstHasArgs.test' and is now 4 in overridden 'SecondChangesArgs.test' method
arguments-differ:298:4:Foo.kwonly_1:Number of parameters was 4 in 'AbstractFoo.kwonly_1' and is now 3 in overridden 'Foo.kwonly_1' method
arguments-differ:301:4:Foo.kwonly_2:Number of parameters was 3 in 'AbstractFoo.kwonly_2' and is now 2 in overridden 'Foo.kwonly_2' method
arguments-differ:304:4:Foo.kwonly_3:Number of parameters was 3 in 'AbstractFoo.kwonly_3' and is now 3 in overridden 'Foo.kwonly_3' method
arguments-differ:307:4:Foo.kwonly_4:Number of parameters was 3 in 'AbstractFoo.kwonly_4' and is now 3 in overridden 'Foo.kwonly_4' method
arguments-differ:310:4:Foo.kwonly_5:Variadics removed in overridden 'Foo.kwonly_5' method
47 changes: 0 additions & 47 deletions tests/functional/a/arguments_differ_py3.py

This file was deleted.

2 changes: 0 additions & 2 deletions tests/functional/a/arguments_differ_py3.rc

This file was deleted.

5 changes: 0 additions & 5 deletions tests/functional/a/arguments_differ_py3.txt

This file was deleted.

74 changes: 74 additions & 0 deletions tests/functional/a/arguments_renamed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pylint: disable = unused-argument, missing-docstring, no-self-use, line-too-long, useless-object-inheritance, too-few-public-methods
import enum


class Condiment(enum.Enum):
CINAMON = 1
SUGAR = 2

class Fruit:
def brew(self, fruit_name: str):
print(f"Brewing a fruit named {fruit_name}")

def eat_with_condiment(self, fruit_name:str, condiment: Condiment):
print(f"Eating a fruit named {fruit_name} with {condiment}")

class Orange(Fruit):
def brew(self, orange_name: str): # [arguments-renamed]
print(f"Brewing an orange named {orange_name}")

def eat_with_condiment(self, orange_name: str, condiment: Condiment()): #[arguments-renamed]
print(f"Eating a fruit named {orange_name} with {condiment}")

class Banana(Fruit):
def brew(self, fruit_name: bool): # No warning here
print(f"Brewing a banana named {fruit_name}")

def eat_with_condiment(self, fruit_name: str, condiment: Condiment, error: str): # [arguments-differ]
print(f"Eating a fruit named {fruit_name} with {condiment}")

class Parent(object):

def test(self, arg):
return arg + 1

def kwargs_test(self, arg, *, var1, var2):
print(f"keyword parameters are {var1} and {var2}.")

class Child(Parent):

def test(self, arg1): # [arguments-renamed]
return arg1 + 1

def kwargs_test(self, arg, *, value1, var2): #[arguments-renamed]
print(f"keyword parameters are {value1} and {var2}.")

class Child2(Parent):

def test(self, var): # [arguments-renamed]
return var + 1

def kwargs_test(self, *, var1, kw2): #[arguments-renamed, arguments-differ]
print(f"keyword parameters are {var1} and {kw2}.")

class ParentDefaults(object):

def test1(self, arg, barg):
print(f"Argument values are {arg} and {barg}")

def test2(self, arg, barg):
print(f"Argument values are {arg} and {barg}!")

def test3(self, arg1, arg2):
print(f"arguments: {arg1} {arg2}")

class ChildDefaults(ParentDefaults):

def test1(self, arg, param2): # [arguments-renamed]
print(f"Argument values are {arg} and {param2}")

def test2(self, _arg, ignored_barg): # no error here
print(f"Argument value is {_arg}")

def test3(self, dummy_param, arg2): # no error here
print(f"arguments: {arg2}")
9 changes: 9 additions & 0 deletions tests/functional/a/arguments_renamed.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
arguments-renamed:17:4:Orange.brew:Parameter 'fruit_name' has been renamed to 'orange_name' in overridden 'Orange.brew' method
arguments-renamed:20:4:Orange.eat_with_condiment:Parameter 'fruit_name' has been renamed to 'orange_name' in overridden 'Orange.eat_with_condiment' method
arguments-differ:27:4:Banana.eat_with_condiment:Number of parameters was 3 in 'Fruit.eat_with_condiment' and is now 4 in overridden 'Banana.eat_with_condiment' method
arguments-renamed:40:4:Child.test:Parameter 'arg' has been renamed to 'arg1' in overridden 'Child.test' method
arguments-renamed:43:4:Child.kwargs_test:Parameter 'var1' has been renamed to 'value1' in overridden 'Child.kwargs_test' method
arguments-renamed:48:4:Child2.test:Parameter 'arg' has been renamed to 'var' in overridden 'Child2.test' method
arguments-differ:51:4:Child2.kwargs_test:Number of parameters was 4 in 'Parent.kwargs_test' and is now 3 in overridden 'Child2.kwargs_test' method
arguments-renamed:51:4:Child2.kwargs_test:Parameter 'var2' has been renamed to 'kw2' in overridden 'Child2.kwargs_test' method
arguments-renamed:67:4:ChildDefaults.test1:Parameter 'barg' has been renamed to 'param2' in overridden 'ChildDefaults.test1' method