7

I have an abstract base class, Animal:

class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def move(self):
        raise NotImplementedError()

    @abc.abstractmethod
    def eat(self):
        raise NotImplementedError()

Now I have another abc that only implements one of these methods:

class Bird(Animal):
    def move(self):
        print("fly")

An another class that implements the missing method:

class Eagle(Bird):
    def eat(self):
        print("eagle eats")

But PyCharm is complaining about Bird that it "must implement all abstract methods", when I intentionally want it to stay abstract still.

Am I missing something, or is this a bug? If it's just a bug, can I ignore the warning somehow (similar to #noqa)?

Markus Meskanen
  • 19,939
  • 18
  • 80
  • 119

1 Answers1

5

Just mark Bird as abstract too:

from abc import ABC

class Bird(Animal, ABC):
    def move(self):
        print("fly")

After thinking about it a little, actually, I think that for this purpose it would make more sense to specify metaclass=ABCMeta, as you did originally, since conceptually we do not want to modify the inheritance hierarchy of Bird, but rather mark it as also an abstract class (for PyCharm's benefit), and perhaps that is a cleaner way of doing so.

gmds
  • 19,325
  • 4
  • 32
  • 58
  • 1
    Right, this doesn't make sense if you think about the inheritance tree imo. Besides, `ABC` only seems to add `metaclass=abc.ABCMeta`, and metaclasses inherit to all subclasses, so this *doesn't do anything* in Python. It did cheat PyCharm though, so thank you! :) – Markus Meskanen May 20 '19 at 11:27
  • 1
    @MarkusMeskanen About inheriting from `ABC`; yup, that's all it does, but I personally find it more convenient than specifying the metaclass explicitly. About the actual effect, you're right that it doesn't actually do anything. However, PyCharm, by default, assumes that all classes that inherit from abstract classes should be concrete, so this tells PyCharm that this class is specifically still meant to be abstract. As for the inheritance hierarchy, since, as you noted, all this does is change the `metaclass`, so perhaps using the metaclass method is better, from a principled perspective ;) – gmds May 20 '19 at 11:29
  • 2
    You're correct, and maybe it's good to "re-declare" it as an ABC, not just for PyCharm but for our clarity too. I 100% agree about the use of `metaclass` over subclassing `ABC`, but unfortunately it didn't cheat PyCharm, it was the first thing I tried before posting the question. I'm not sure why subclassing `ABC` works but re-defining the metaclass doesn't, but I'm glad you came up with it. – Markus Meskanen May 20 '19 at 11:35
  • 1
    There seems to be a bug report already, maybe it'll be fixed: https://youtrack.jetbrains.com/issue/PY-33830 For now I'm good with your proposed solution – Markus Meskanen May 20 '19 at 11:40
  • @MarkusMeskanen I see, so it is a bug. Given what you've tried, it certainly sounds like one. I actually also stumbled upon this solution purely by chance earlier, since I had this exact same problem. Lucky, I guess! – gmds May 20 '19 at 11:41