20

Pylint generates this error for subclasses of an abstract class, even when those subclasses are not themselves instantiated and the methods are overridden in the concrete subclasses. Why does Pylint think my abstract subclasses are intended to be concrete? How can I shut up this warning without getting out the hammer and disabling it altogether in the rc file?

AdamC
  • 457
  • 1
  • 4
  • 14
  • 5
    Note: Not exactly the same issue but for the record, I get this warning when a method that raises `NotImplementedError` in an abstract class is not overridden in the child class, even if the `@abstractmethod` decorator on the abstract method is commented. – Jérôme Oct 25 '17 at 15:48
  • 1
    In Python 3.7 and Pylint 2.3.1, I get this error when a method of an abstract class raises `NotImplementedError` at all and is subclassed without overriding it, even if it's not possible for that method to ever be called and it isn't decorated with `@abstractmethod`. – Soren Bjornstad Aug 10 '19 at 03:19

3 Answers3

29

For some reason pylint think the class isn't abstract (currenly detection is done by checking for method which raise NotImplementedError). Adding a comment like #pylint: disable=W0223 at the top of the module (for disabling only in this module) or class (only in this class), should do the trick.

sthenault
  • 14,397
  • 5
  • 38
  • 32
  • 9
    OK, so the answer is that pylint's detection mechanism is flawed, since it doesn't consider the metaclass. I knew I could disable at the module level, but it doesn't seem like a useful check in its current form. – AdamC Mar 07 '14 at 18:49
5

In order to shut up the wrong abstract-method warning you can implement abstract classes with abc.ABC superclass instead of using abc.ABCMeta metaclass.

For example, this code will raise the warning:

from abc import ABCMeta, abstractmethod


class Parent:
    __metaclass__ = ABCMeta

    @abstractmethod
    def do_something(self):
        pass


class Child(Parent):
    __metaclass__ = ABCMeta

but this will not:

from abc import ABC, abstractmethod


class Parent(ABC):

    @abstractmethod
    def do_something(self):
        pass


class Child(Parent, ABC):
    pass

Caution! With ABC superclass and multiple inheritance you have to watch out for potential Method Resolution Order (MRO) problems.

Michał Jabłoński
  • 1,129
  • 1
  • 13
  • 15
  • Your solution is not an workaround. It does only not raise the warning, because it doesn't override the `__init__` method at all. – Sukombu Jul 24 '22 at 16:38
0

I agree with Michal that you should use ABCMeta. I think the way it's used in this example is now considered the better way to use it.

from abc import ABCMeta, abstractmethod


class Bird( metaclass=ABCMeta ) :
    '''It's a bird'''

    def __init__(self, name : str ) :
        self._name = name

    @abstractmethod
    def talk(self) :
        '''Talk as as appropriate'''

    @abstractmethod
    def walk(self) :
        ...

# No warning here. The abstract method walk is inherited,
# but this class is declared abstract, so that's ok.
class Duck( Bird, metaclass=ABCMeta ) :
    '''Talks like a duck'''
    def talk(self) :
        return "quack"

# Pylint warns here. The abstract method walk is inherited.
# This class is not declared abstract, but it is abstract because
# it has inherited an abstract method.
class Mallard( Duck ) :
    '''It's really just a Duck, but concrete'''


def main() :
    d = Duck( "Donald" ) # Pylint warns here because Duck is abstract
    m = Mallard( "Moe" ) # Pylint warns here because Mallard is abstract
    # even though it was not declared as such.

This style is very much like Java in that abstract classes should be declared as such. The only difference is that in Java you don't get the final warning because in Java a class is concrete unless declared abstract.

Theodore Norvell
  • 15,366
  • 6
  • 31
  • 45