36

Pylint raises the warning: Useless super delegation in method '__init__' (useless-super-delegation) for the SpecificError class below.

class MyProjectExceptions(Exception):
    """The base class for all my project's exceptions."""
    def __init__(self, message, func):
        super(MyProjectExceptions, self).__init__(message)  # Normal exception handling
        self.func = func  # Error origin for logging

class SpecificError(MyProjectExceptions):
    """Raise when a specific error occurs."""
    def __init__(self, message, func):
        super(SpecificError, self).__init__(message, func)

What is the correct way to pass the parameters to the superclass here?

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
mugwump
  • 436
  • 1
  • 4
  • 10
  • 1
    Why does `SpecificError` have its own `__init__`? You could just delete that method entirely and use the inherited implementation. (Unlike some other languages, `__init__` is inherited like any other method in Python.) – user2357112 Aug 09 '17 at 22:22
  • 1
    So would the best practice then be to omit the `__init__` entirely leaving only the docstring or replace it with `pass`? – mugwump Aug 09 '17 at 22:27
  • Related: [Pylint issues useless-super-delegation instead of useless-constructor](https://github.com/PyCQA/pylint/issues/1567) – Stevoisiak Jun 25 '18 at 16:32

2 Answers2

47

If you call the SpecificError class it will look for an __init__. If it doesn't exist it will call the parent's __init__. There is no need to add an __init__ here, since it's exactly the same like the parent class. It is basically code duplication.

You should do:

class SpecificError(MyProjectExceptions):
    """Raise when a specific error occurs."""
ericbn
  • 10,163
  • 3
  • 47
  • 55
Xalio08
  • 973
  • 10
  • 17
  • However by doing that I doubt that the class types will be correct under all scenarios. I wonder if isinstance and friends would work – Har Jun 12 '18 at 14:09
  • But if there are parameters required by the constructor please mention them in the class docstring. Otherwise you have no idea what parameters are required. – anilbey Sep 01 '21 at 15:24
  • 1
    The `pass` is not necessary either. Pylint will also complain about it with " W0107: Unnecessary pass statement (unnecessary-pass)" – ericbn Sep 21 '21 at 00:28
  • what if the specific error has a default value for the message passed to init? – The Fool Jun 12 '22 at 15:58
  • @TheFool - well then you should override `__init__` in `SpecificError` and you should no longer get the pylint warning because you _are_ doing something different to the base class's constructor. – snark Jul 15 '22 at 09:35
18

As Mathieu mentioned, you don't need to override __init__ in SpecificError since you are only calling super().

class MyProjectExceptions(Exception):
    """The base class for all my project's exceptions."""
    def __init__(self, message, func):
        super(MyProjectExceptions, self).__init__(message)  # Normal exception handling
        self.func = func  # Error origin for logging

class SpecificError(MyProjectExceptions):
    """Raise when a specific error occurs."""

Pylint's developers explain useless-super-delegation in a bit more depth on the Pylint changelog:

useless-super-delegation [is] used whenever we can detect that an overridden method is useless, relying on super() delegation to do the same thing as another method from the MRO.

For instance, in this example, the first two methods are useless, since they do the exact same thing as the methods from the base classes, while the next two methods are not, since they do some extra operations with the passed arguments.

class Impl(Base):

    def __init__(self, param1, param2):
        super(Impl, self).__init__(param1, param2)

    def useless(self, first, second):
        return super(Impl, self).useless(first, second)

    def not_useless(self, first, **kwargs):
        debug = kwargs.pop('debug', False)
        if debug:
            ...
        return super(Impl, self).not_useless(first, **kwargs)

    def not_useless_1(self, first, *args):
        return super(Impl, self).not_useless_1(first + some_value, *args)

What's New In Pylint 1.7

The warning's creator further explains in a commit message:

This is used whenever pylint can detect than an overridden method is useless, relying on super() delegation to implement the same thing as another method from MRO. In this case, it is enough to not implement the given method and let it be propagated to the another implementation from the MRO.

For the original issue report, see #839 - Pylint rule against people overriding a method just to call super.

Stevoisiak
  • 23,794
  • 27
  • 122
  • 225