Skip to content

Commit d150e39

Browse files
ksaketoupre-commit-ci[bot]Pierre-Sassoulas
authored
Create new error arguments-renamed (#4467)
* Create new error arguments-renamed This commits creates the new error arguments-renamed based on the functionality added on #4422 and the changes of #4456. * Merge test files for arguments-differ This commit merges the two kinds of test files that existed for the arguments-differ error, since now all tests run in Python3. * Add tests for arguments-renamed error * Add new error arguments-renamed Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Pierre Sassoulas <[email protected]>
1 parent 18ef7ba commit d150e39

10 files changed

+175
-74
lines changed

ChangeLog

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ modules are added.
3535

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

38+
* Created new error message called ``arguments-renamed`` which identifies any changes at the parameter
39+
names of overridden functions.
40+
41+
Closes #3536
42+
3843
* New checker ``consider-using-dict-items``. Emitted when iterating over dictionary keys and then
3944
indexing the same dictionary with the key within loop body.
4045

doc/whatsnew/2.9.rst

+3
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,7 @@ Other Changes
2727

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

30+
* A new error called ``arguments-renamed`` has been created, which identifies any changes at the parameter names
31+
of overridden functions. It aims to separate the functionality of ``arguments-differ``.
32+
3033
* Fix incompatibility with Python 3.6.0 caused by ``typing.Counter`` and ``typing.NoReturn`` usage

pylint/checkers/classes.py

+29-18
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ def _different_parameters(
342342
output_messages.append("Number of parameters ")
343343
output_messages += different_positional[1:]
344344
output_messages += different_kwonly[1:]
345+
else:
346+
output_messages += different_positional
347+
output_messages += different_kwonly
345348
else:
346349
if different_positional:
347350
output_messages += different_positional
@@ -627,6 +630,12 @@ def _has_same_layout_slots(slots, assigned_value):
627630
"that does not match its base class "
628631
"which could result in potential bugs at runtime.",
629632
),
633+
"W0237": (
634+
"%s %s %r method",
635+
"arguments-renamed",
636+
"Used when a method parameter has a different name than in "
637+
"the implemented interface or in an overridden method.",
638+
),
630639
"E0236": (
631640
"Invalid object %r in __slots__, must contain only non empty strings",
632641
"invalid-slots-object",
@@ -1810,27 +1819,29 @@ def _check_signature(self, method1, refmethod, class_type, cls):
18101819
total_args_refmethod += 1
18111820
if refmethod.args.kwonlyargs:
18121821
total_args_refmethod += len(refmethod.args.kwonlyargs)
1813-
self.add_message(
1814-
"arguments-differ",
1815-
args=(
1816-
msg
1817-
+ f"was {total_args_refmethod} in '{refmethod.parent.name}.{refmethod.name}' and "
1818-
f"is now {total_args_method1} in",
1819-
class_type,
1820-
str(method1.parent.name) + "." + str(method1.name),
1821-
),
1822-
node=method1,
1822+
error_type = "arguments-differ"
1823+
msg_args = (
1824+
msg
1825+
+ f"was {total_args_refmethod} in '{refmethod.parent.name}.{refmethod.name}' and "
1826+
f"is now {total_args_method1} in",
1827+
class_type,
1828+
f"{method1.parent.name}.{method1.name}",
1829+
)
1830+
elif "renamed" in msg:
1831+
error_type = "arguments-renamed"
1832+
msg_args = (
1833+
msg,
1834+
class_type,
1835+
f"{method1.parent.name}.{method1.name}",
18231836
)
18241837
else:
1825-
self.add_message(
1826-
"arguments-differ",
1827-
args=(
1828-
msg,
1829-
class_type,
1830-
str(method1.parent.name) + "." + str(method1.name),
1831-
),
1832-
node=method1,
1838+
error_type = "arguments-differ"
1839+
msg_args = (
1840+
msg,
1841+
class_type,
1842+
f"{method1.parent.name}.{method1.name}",
18331843
)
1844+
self.add_message(error_type, args=msg_args, node=method1)
18341845
elif (
18351846
len(method1.args.defaults) < len(refmethod.args.defaults)
18361847
and not method1.args.vararg

tests/functional/a/arguments_differ.py

+49-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class VarargsChild(Varargs):
6868
def has_kwargs(self, arg): # [arguments-differ]
6969
"Not okay to lose capabilities. Also, type has changed."
7070

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

7474

@@ -270,3 +270,51 @@ def func(self, user_input: FooT1) -> None:
270270
class ChildT3(ParentT3):
271271
def func(self, user_input: FooT1) -> None:
272272
pass
273+
274+
# Keyword and positional overriddes
275+
class AbstractFoo:
276+
277+
def kwonly_1(self, first, *, second, third):
278+
"Normal positional with two positional only params."
279+
280+
def kwonly_2(self, *, first, second):
281+
"Two positional only parameter."
282+
283+
def kwonly_3(self, *, first, second):
284+
"Two positional only params."
285+
286+
def kwonly_4(self, *, first, second=None):
287+
"One positional only and another with a default."
288+
289+
def kwonly_5(self, *, first, **kwargs):
290+
"Keyword only and keyword variadics."
291+
292+
def kwonly_6(self, first, second, *, third):
293+
"Two positional and one keyword"
294+
295+
296+
class Foo(AbstractFoo):
297+
298+
def kwonly_1(self, first, *, second): # [arguments-differ]
299+
"One positional and only one positional only param."
300+
301+
def kwonly_2(self, *, first): # [arguments-differ]
302+
"Only one positional parameter instead of two positional only parameters."
303+
304+
def kwonly_3(self, first, second): # [arguments-differ]
305+
"Two positional params."
306+
307+
def kwonly_4(self, first, second): # [arguments-differ]
308+
"Two positional params."
309+
310+
def kwonly_5(self, *, first): # [arguments-differ]
311+
"Keyword only, but no variadics."
312+
313+
def kwonly_6(self, *args, **kwargs): # valid override
314+
"Positional and keyword variadics to pass through parent params"
315+
316+
317+
class Foo2(AbstractFoo):
318+
319+
def kwonly_6(self, first, *args, **kwargs): # valid override
320+
"One positional with the rest variadics to pass through parent params"

tests/functional/a/arguments_differ.txt

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,10 @@ arguments-differ:12:4:Child.test:Number of parameters was 1 in 'Parent.test' and
22
arguments-differ:23:4:ChildDefaults.test:Number of parameters was 3 in 'ParentDefaults.test' and is now 2 in overridden 'ChildDefaults.test' method
33
arguments-differ:41:4:ClassmethodChild.func:Number of parameters was 2 in 'Classmethod.func' and is now 0 in overridden 'ClassmethodChild.func' method
44
arguments-differ:68:4:VarargsChild.has_kwargs:Variadics removed in overridden 'VarargsChild.has_kwargs' method
5-
arguments-differ:71:4:VarargsChild.no_kwargs:Parameter 'args' has been renamed to 'arg' in overridden 'VarargsChild.no_kwargs' method
5+
arguments-renamed:71:4:VarargsChild.no_kwargs:Parameter 'args' has been renamed to 'arg' in overridden 'VarargsChild.no_kwargs' method
66
arguments-differ:172:4:SecondChangesArgs.test:Number of parameters was 2 in 'FirstHasArgs.test' and is now 4 in overridden 'SecondChangesArgs.test' method
7+
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
8+
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
9+
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
10+
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
11+
arguments-differ:310:4:Foo.kwonly_5:Variadics removed in overridden 'Foo.kwonly_5' method

tests/functional/a/arguments_differ_py3.py

-47
This file was deleted.

tests/functional/a/arguments_differ_py3.rc

-2
This file was deleted.

tests/functional/a/arguments_differ_py3.txt

-5
This file was deleted.
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#pylint: disable = unused-argument, missing-docstring, no-self-use, line-too-long, useless-object-inheritance, too-few-public-methods
2+
import enum
3+
4+
5+
class Condiment(enum.Enum):
6+
CINAMON = 1
7+
SUGAR = 2
8+
9+
class Fruit:
10+
def brew(self, fruit_name: str):
11+
print(f"Brewing a fruit named {fruit_name}")
12+
13+
def eat_with_condiment(self, fruit_name:str, condiment: Condiment):
14+
print(f"Eating a fruit named {fruit_name} with {condiment}")
15+
16+
class Orange(Fruit):
17+
def brew(self, orange_name: str): # [arguments-renamed]
18+
print(f"Brewing an orange named {orange_name}")
19+
20+
def eat_with_condiment(self, orange_name: str, condiment: Condiment()): #[arguments-renamed]
21+
print(f"Eating a fruit named {orange_name} with {condiment}")
22+
23+
class Banana(Fruit):
24+
def brew(self, fruit_name: bool): # No warning here
25+
print(f"Brewing a banana named {fruit_name}")
26+
27+
def eat_with_condiment(self, fruit_name: str, condiment: Condiment, error: str): # [arguments-differ]
28+
print(f"Eating a fruit named {fruit_name} with {condiment}")
29+
30+
class Parent(object):
31+
32+
def test(self, arg):
33+
return arg + 1
34+
35+
def kwargs_test(self, arg, *, var1, var2):
36+
print(f"keyword parameters are {var1} and {var2}.")
37+
38+
class Child(Parent):
39+
40+
def test(self, arg1): # [arguments-renamed]
41+
return arg1 + 1
42+
43+
def kwargs_test(self, arg, *, value1, var2): #[arguments-renamed]
44+
print(f"keyword parameters are {value1} and {var2}.")
45+
46+
class Child2(Parent):
47+
48+
def test(self, var): # [arguments-renamed]
49+
return var + 1
50+
51+
def kwargs_test(self, *, var1, kw2): #[arguments-renamed, arguments-differ]
52+
print(f"keyword parameters are {var1} and {kw2}.")
53+
54+
class ParentDefaults(object):
55+
56+
def test1(self, arg, barg):
57+
print(f"Argument values are {arg} and {barg}")
58+
59+
def test2(self, arg, barg):
60+
print(f"Argument values are {arg} and {barg}!")
61+
62+
def test3(self, arg1, arg2):
63+
print(f"arguments: {arg1} {arg2}")
64+
65+
class ChildDefaults(ParentDefaults):
66+
67+
def test1(self, arg, param2): # [arguments-renamed]
68+
print(f"Argument values are {arg} and {param2}")
69+
70+
def test2(self, _arg, ignored_barg): # no error here
71+
print(f"Argument value is {_arg}")
72+
73+
def test3(self, dummy_param, arg2): # no error here
74+
print(f"arguments: {arg2}")
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
arguments-renamed:17:4:Orange.brew:Parameter 'fruit_name' has been renamed to 'orange_name' in overridden 'Orange.brew' method
2+
arguments-renamed:20:4:Orange.eat_with_condiment:Parameter 'fruit_name' has been renamed to 'orange_name' in overridden 'Orange.eat_with_condiment' method
3+
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
4+
arguments-renamed:40:4:Child.test:Parameter 'arg' has been renamed to 'arg1' in overridden 'Child.test' method
5+
arguments-renamed:43:4:Child.kwargs_test:Parameter 'var1' has been renamed to 'value1' in overridden 'Child.kwargs_test' method
6+
arguments-renamed:48:4:Child2.test:Parameter 'arg' has been renamed to 'var' in overridden 'Child2.test' method
7+
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
8+
arguments-renamed:51:4:Child2.kwargs_test:Parameter 'var2' has been renamed to 'kw2' in overridden 'Child2.kwargs_test' method
9+
arguments-renamed:67:4:ChildDefaults.test1:Parameter 'barg' has been renamed to 'param2' in overridden 'ChildDefaults.test1' method

0 commit comments

Comments
 (0)