Skip to content

Rename useless-super-delegation to useless-parent-delegation #6955

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

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
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ def eat(self, food):

class Human(Animal):

def eat(self, food): # [useless-super-delegation]
def eat(self, food): # [useless-parent-delegation]
super(Human, self).eat(food)
4 changes: 4 additions & 0 deletions doc/whatsnew/2/2.15/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ Other bug fixes
Other Changes
=============

* ``useless-super-delegation`` has been renamed to ``useless-parent-delegation`` in order to be more generic.

Closes #6953


Internal changes
================
Expand Down
20 changes: 11 additions & 9 deletions pylint/checkers/classes/class_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def _signature_from_call(call):
for keyword in call.keywords or []:
arg, value = keyword.arg, keyword.value
if arg is None and isinstance(value, nodes.Name):
# Starred node and we are interested only in names,
# Starred node, and we are interested only in names,
# otherwise some transformation might occur for the parameter.
starred_kws.append(value.name)
elif isinstance(value, nodes.Name):
Expand Down Expand Up @@ -470,9 +470,7 @@ def _has_same_layout_slots(slots, assigned_value):
return False


MSGS: dict[
str, MessageDefinitionTuple
] = { # pylint: disable=consider-using-namedtuple-or-dataclass
MSGS: dict[str, MessageDefinitionTuple] = {
"F0202": (
"Unable to check methods signature (%s / %s)",
"method-check-failed",
Expand Down Expand Up @@ -579,12 +577,13 @@ def _has_same_layout_slots(slots, assigned_value):
"Used when an __init__ method is called on a class which is not "
"in the direct ancestors for the analysed class.",
),
"W0235": (
"Useless super delegation in method %r",
"useless-super-delegation",
"W0246": (
"Useless parent or super() delegation in method %r",
"useless-parent-delegation",
"Used whenever we can detect that an overridden method is useless, "
"relying on super() delegation to do the same thing as another method "
"relying on parent or super() delegation to do the same thing as another method "
"from the MRO.",
{"old_names": [("W0235", "useless-super-delegation")]},
Copy link
Member Author

@Pierre-Sassoulas Pierre-Sassoulas Jun 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a tuple here trip up the check for consider-using-namedtuple-or-dataclass for the whole surrounding dict.

),
"W0236": (
"Method %r was expected to be %r, found it instead as %r",
Expand Down Expand Up @@ -1305,7 +1304,10 @@ def form_annotations(arguments):

if _definition_equivalent_to_call(params, args):
self.add_message(
"useless-super-delegation", node=function, args=(function.name,)
"useless-parent-delegation",
node=function,
args=(function.name,),
confidence=INFERENCE,
)

def _check_property_with_parameters(self, node):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
# pylint: disable=line-too-long, useless-object-inheritance, arguments-out-of-order
# pylint: disable=super-with-arguments, dangerous-default-value

import random
from typing import Any, List

default_var = 1


def not_a_method(param, param2):
return super(None, None).not_a_method(param, param2)

Expand Down Expand Up @@ -65,8 +70,8 @@ def with_default_arg_quad(self, first, default_arg="has_been_changed"):
def with_default_unhandled(self, first, default_arg=lambda: True):
super().with_default_arg_quad(first, default_arg)

class NotUselessSuper(Base):

class NotUselessSuper(Base):
def multiple_statements(self):
first = 42 * 24
return super().multiple_statements() + first
Expand Down Expand Up @@ -117,14 +122,13 @@ def not_passing_default(self, first, second=None):
return super(NotUselessSuper, self).not_passing_default(first)

def passing_only_a_handful(self, first, second, third, fourth):
return super(NotUselessSuper, self).passing_only_a_handful(
first, second)
return super(NotUselessSuper, self).passing_only_a_handful(first, second)

def not_the_same_order(self, first, second, third):
return super(NotUselessSuper, self).not_the_same_order(third, first, second)

def no_kwargs_in_signature(self, key=None):
values = {'key': 'something'}
values = {"key": "something"}
return super(NotUselessSuper, self).no_kwargs_in_signature(**values)

def no_args_in_signature(self, first, second):
Expand All @@ -133,18 +137,16 @@ def no_args_in_signature(self, first, second):

def variadics_with_multiple_keyword_arguments(self, **kwargs):
return super(NotUselessSuper, self).variadics_with_multiple_keyword_arguments(
first=None,
second=None,
**kwargs)
first=None, second=None, **kwargs
)

def extraneous_keyword_params(self, none_ok=False):
super(NotUselessSuper, self).extraneous_keyword_params(
none_ok,
valid_values=[23, 42])
none_ok, valid_values=[23, 42]
)

def extraneous_positional_args(self, **args):
super(NotUselessSuper, self).extraneous_positional_args(
1, 2, **args)
super(NotUselessSuper, self).extraneous_positional_args(1, 2, **args)

def with_default_argument(self, first, default_arg="other"):
# Not useless because the default_arg is different from the one in the base class
Expand All @@ -154,7 +156,7 @@ def without_default_argument(self, first, second=True):
# Not useless because in the base class there is not default value for second argument
super(NotUselessSuper, self).without_default_argument(first, second)

def with_default_argument_none(self, first, default_arg='NotNone'):
def with_default_argument_none(self, first, default_arg="NotNone"):
# Not useless because the default_arg is different from the one in the base class
super(NotUselessSuper, self).with_default_argument_none(first, default_arg)

Expand All @@ -170,19 +172,22 @@ def with_default_argument_tuple(self, first, default_arg=("42", "a")):
# Not useless because the default_arg is different from the one in the base class
super(NotUselessSuper, self).with_default_argument_tuple(first, default_arg)

def with_default_argument_dict(self, first, default_arg={'foo': 'bar'}):
def with_default_argument_dict(self, first, default_arg={"foo": "bar"}):
# Not useless because the default_arg is different from the one in the base class
super(NotUselessSuper, self).with_default_argument_dict(first, default_arg)

default_var = 2

def with_default_argument_var(self, first, default_arg=default_var):
# Not useless because the default_arg refers to a different variable from the one in the base class
super(NotUselessSuper, self).with_default_argument_var(first, default_arg)

def with_default_argument_bis(self, first, default_arg="default"):
# Although the default_arg is the same as in the base class, the call signature
# differs. Thus it is not useless.
super(NotUselessSuper, self).with_default_argument_bis(default_arg + "_argument")
super(NotUselessSuper, self).with_default_argument_bis(
default_arg + "_argument"
)

def fake_method(self, param2="other"):
super(NotUselessSuper, self).fake_method(param2)
Expand All @@ -202,72 +207,73 @@ def with_default_arg_ter(self, first, default_arg="has_been_changed_again"):
def with_default_arg_quad(self, first, default_arg="has_been_changed"):
# Not useless because the default value is the same as in the base but the
# call is different from the signature
super(NotUselessSuper, self).with_default_arg_quad(first, default_arg + "_and_modified")
super(NotUselessSuper, self).with_default_arg_quad(
first, default_arg + "_and_modified"
)

def with_default_unhandled(self, first, default_arg=lambda: True):
# Not useless because the default value type is not explicitly handled (Lambda), so assume they are different
super(NotUselessSuper, self).with_default_unhandled(first, default_arg)


class UselessSuper(Base):

def equivalent_params(self): # [useless-super-delegation]
def equivalent_params(self): # [useless-parent-delegation]
return super(UselessSuper, self).equivalent_params()

def equivalent_params_1(self, first): # [useless-super-delegation]
def equivalent_params_1(self, first): # [useless-parent-delegation]
return super(UselessSuper, self).equivalent_params_1(first)

def equivalent_params_2(self, *args): # [useless-super-delegation]
def equivalent_params_2(self, *args): # [useless-parent-delegation]
return super(UselessSuper, self).equivalent_params_2(*args)

def equivalent_params_3(self, *args, **kwargs): # [useless-super-delegation]
def equivalent_params_3(self, *args, **kwargs): # [useless-parent-delegation]
return super(UselessSuper, self).equivalent_params_3(*args, **kwargs)

def equivalent_params_4(self, first): # [useless-super-delegation]
def equivalent_params_4(self, first): # [useless-parent-delegation]
super(UselessSuper, self).equivalent_params_4(first)

def equivalent_params_5(self, first, *args): # [useless-super-delegation]
def equivalent_params_5(self, first, *args): # [useless-parent-delegation]
super(UselessSuper, self).equivalent_params_5(first, *args)

def equivalent_params_6(self, first, *args, **kwargs): # [useless-super-delegation]
def equivalent_params_6(self, first, *args, **kwargs): # [useless-parent-delegation]
return super(UselessSuper, self).equivalent_params_6(first, *args, **kwargs)

def with_default_argument(self, first, default_arg="default"): # [useless-super-delegation]
def with_default_argument(self, first, default_arg="default"): # [useless-parent-delegation]
# useless because the default value here is the same as in the base class
return super(UselessSuper, self).with_default_argument(first, default_arg)

def without_default_argument(self, first, second): # [useless-super-delegation]
def without_default_argument(self, first, second): # [useless-parent-delegation]
return super(UselessSuper, self).without_default_argument(first, second)

def with_default_argument_none(self, first, default_arg=None): # [useless-super-delegation]
def with_default_argument_none(self, first, default_arg=None): # [useless-parent-delegation]
# useless because the default value here is the same as in the base class
super(UselessSuper, self).with_default_argument_none(first, default_arg)

def with_default_argument_int(self, first, default_arg=42): # [useless-super-delegation]
def with_default_argument_int(self, first, default_arg=42): # [useless-parent-delegation]
super(UselessSuper, self).with_default_argument_int(first, default_arg)

def with_default_argument_tuple(self, first, default_arg=()): # [useless-super-delegation]
def with_default_argument_tuple(self, first, default_arg=()): # [useless-parent-delegation]
super(UselessSuper, self).with_default_argument_tuple(first, default_arg)

def with_default_argument_dict(self, first, default_arg={}): # [useless-super-delegation]
def with_default_argument_dict(self, first, default_arg={}): # [useless-parent-delegation]
super(UselessSuper, self).with_default_argument_dict(first, default_arg)

def with_default_argument_var(self, first, default_arg=default_var): # [useless-super-delegation]
def with_default_argument_var(self, first, default_arg=default_var): # [useless-parent-delegation]
super(UselessSuper, self).with_default_argument_var(first, default_arg)

def __init__(self): # [useless-super-delegation]
def __init__(self): # [useless-parent-delegation]
super(UselessSuper, self).__init__()

def with_default_arg(self, first, default_arg="only_in_super_base"): # [useless-super-delegation]
def with_default_arg(self, first, default_arg="only_in_super_base"): # [useless-parent-delegation]
super(UselessSuper, self).with_default_arg(first, default_arg)

def with_default_arg_bis(self, first, default_arg="only_in_super_base"): # [useless-super-delegation]
def with_default_arg_bis(self, first, default_arg="only_in_super_base"): # [useless-parent-delegation]
super(UselessSuper, self).with_default_arg_bis(first, default_arg)

def with_default_arg_ter(self, first, default_arg="has_been_changed"): # [useless-super-delegation]
def with_default_arg_ter(self, first, default_arg="has_been_changed"): # [useless-parent-delegation]
super(UselessSuper, self).with_default_arg_ter(first, default_arg)

def with_default_arg_quad(self, first, default_arg="has_been_changed"): # [useless-super-delegation]
def with_default_arg_quad(self, first, default_arg="has_been_changed"): # [useless-parent-delegation]
super(UselessSuper, self).with_default_arg_quad(first, default_arg)


Expand All @@ -276,7 +282,7 @@ def trigger_something(value_to_trigger):


class NotUselessSuperDecorators(Base):
@trigger_something('value1')
@trigger_something("value1")
def method_decorated(self):
super(NotUselessSuperDecorators, self).method_decorated()

Expand All @@ -299,9 +305,9 @@ def __hash__(self):

class DecoratedList(MyList):
def __str__(self):
return f'List -> {super().__str__()}'
return f"List -> {super().__str__()}"

def __hash__(self): # [useless-super-delegation]
def __hash__(self): # [useless-parent-delegation]
return super().__hash__()


Expand All @@ -327,10 +333,83 @@ def __init__(self, a, *args):


class SubTwoOne(SuperTwo):
def __init__(self, a, *args): # [useless-super-delegation]
def __init__(self, a, *args): # [useless-parent-delegation]
super().__init__(a, *args)


class SubTwoTwo(SuperTwo):
def __init__(self, a, b, *args):
super().__init__(a, b, *args)


class NotUselessSuperPy3(object):
def not_passing_keyword_only(self, first, *, second):
return super().not_passing_keyword_only(first)

def passing_keyword_only_with_modifications(self, first, *, second):
return super().passing_keyword_only_with_modifications(first, second + 1)


class AlsoNotUselessSuperPy3(NotUselessSuperPy3):
def not_passing_keyword_only(self, first, *, second="second"):
return super().not_passing_keyword_only(first, second=second)


class UselessSuperPy3(object):
def useless(self, *, first): # [useless-parent-delegation]
super().useless(first=first)


class Egg():
def __init__(self, thing: object) -> None:
pass


class Spam(Egg):
def __init__(self, thing: int) -> None:
super().__init__(thing)


class Ham(Egg):
def __init__(self, thing: object) -> None: # [useless-parent-delegation]
super().__init__(thing)


class Test:
def __init__(self, _arg: List[int]) -> None:
super().__init__()


class ReturnTypeAny:
choices = ["a", 1, (2, 3)]

def draw(self) -> Any:
return random.choice(self.choices)


class ReturnTypeNarrowed(ReturnTypeAny):
choices = [1, 2, 3]

def draw(self) -> int:
return super().draw()


class NoReturnType:
choices = ["a", 1, (2, 3)]

def draw(self):
return random.choice(self.choices)


class ReturnTypeSpecified(NoReturnType):
choices = ["a", "b"]

def draw(self) -> str: # [useless-parent-delegation]
return super().draw()


class ReturnTypeSame(ReturnTypeAny):
choices = ["a", "b"]

def draw(self) -> Any: # [useless-parent-delegation]
return super().draw()
25 changes: 25 additions & 0 deletions tests/functional/u/useless/useless_parent_delegation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
useless-parent-delegation:220:4:220:25:UselessSuper.equivalent_params:Useless parent or super() delegation in method 'equivalent_params':INFERENCE
useless-parent-delegation:223:4:223:27:UselessSuper.equivalent_params_1:Useless parent or super() delegation in method 'equivalent_params_1':INFERENCE
useless-parent-delegation:226:4:226:27:UselessSuper.equivalent_params_2:Useless parent or super() delegation in method 'equivalent_params_2':INFERENCE
useless-parent-delegation:229:4:229:27:UselessSuper.equivalent_params_3:Useless parent or super() delegation in method 'equivalent_params_3':INFERENCE
useless-parent-delegation:232:4:232:27:UselessSuper.equivalent_params_4:Useless parent or super() delegation in method 'equivalent_params_4':INFERENCE
useless-parent-delegation:235:4:235:27:UselessSuper.equivalent_params_5:Useless parent or super() delegation in method 'equivalent_params_5':INFERENCE
useless-parent-delegation:238:4:238:27:UselessSuper.equivalent_params_6:Useless parent or super() delegation in method 'equivalent_params_6':INFERENCE
useless-parent-delegation:241:4:241:29:UselessSuper.with_default_argument:Useless parent or super() delegation in method 'with_default_argument':INFERENCE
useless-parent-delegation:245:4:245:32:UselessSuper.without_default_argument:Useless parent or super() delegation in method 'without_default_argument':INFERENCE
useless-parent-delegation:248:4:248:34:UselessSuper.with_default_argument_none:Useless parent or super() delegation in method 'with_default_argument_none':INFERENCE
useless-parent-delegation:252:4:252:33:UselessSuper.with_default_argument_int:Useless parent or super() delegation in method 'with_default_argument_int':INFERENCE
useless-parent-delegation:255:4:255:35:UselessSuper.with_default_argument_tuple:Useless parent or super() delegation in method 'with_default_argument_tuple':INFERENCE
useless-parent-delegation:258:4:258:34:UselessSuper.with_default_argument_dict:Useless parent or super() delegation in method 'with_default_argument_dict':INFERENCE
useless-parent-delegation:261:4:261:33:UselessSuper.with_default_argument_var:Useless parent or super() delegation in method 'with_default_argument_var':INFERENCE
useless-parent-delegation:264:4:264:16:UselessSuper.__init__:Useless parent or super() delegation in method '__init__':INFERENCE
useless-parent-delegation:267:4:267:24:UselessSuper.with_default_arg:Useless parent or super() delegation in method 'with_default_arg':INFERENCE
useless-parent-delegation:270:4:270:28:UselessSuper.with_default_arg_bis:Useless parent or super() delegation in method 'with_default_arg_bis':INFERENCE
useless-parent-delegation:273:4:273:28:UselessSuper.with_default_arg_ter:Useless parent or super() delegation in method 'with_default_arg_ter':INFERENCE
useless-parent-delegation:276:4:276:29:UselessSuper.with_default_arg_quad:Useless parent or super() delegation in method 'with_default_arg_quad':INFERENCE
useless-parent-delegation:310:4:310:16:DecoratedList.__hash__:Useless parent or super() delegation in method '__hash__':INFERENCE
useless-parent-delegation:336:4:336:16:SubTwoOne.__init__:Useless parent or super() delegation in method '__init__':INFERENCE
useless-parent-delegation:359:4:359:15:UselessSuperPy3.useless:Useless parent or super() delegation in method 'useless':INFERENCE
useless-parent-delegation:374:4:374:16:Ham.__init__:Useless parent or super() delegation in method '__init__':INFERENCE
useless-parent-delegation:407:4:407:12:ReturnTypeSpecified.draw:Useless parent or super() delegation in method 'draw':INFERENCE
useless-parent-delegation:414:4:414:12:ReturnTypeSame.draw:Useless parent or super() delegation in method 'draw':INFERENCE
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ def __init__(self, first: float, /, second: float) -> None:


class Ham(Egg):
def __init__(self, first: Any, /, second: Any) -> None: # [useless-super-delegation]
def __init__(self, first: Any, /, second: Any) -> None: # [useless-parent-delegation]
super().__init__(first, second)
Loading