2

Consider this code

from abc import ABCMeta, abstractmethod

class C():
    @abstractmethod
    def my_abstract_method(self):
        print('foo')

class D(C):
    pass

x = C()
y = D()

Neither x nor y is allowed by mypy yielding me a

test.py:13: error: Cannot instantiate abstract class 'C' with abstract attribute 'my_abstract_method'
test.py:15: error: Cannot instantiate abstract class 'D' with abstract attribute 'my_abstract_method'

I'm testing this with mypy 0.570 and python 3.6.3

However, the documentation says that I'd need to set metaclass=ABCMeta for that to work. What am I missing?

Christoph
  • 26,519
  • 28
  • 95
  • 133
  • Which Python version ? I can't reproduce this behaviour on 2.7.x nor on 3.4.3 – bruno desthuilliers Mar 15 '18 at 11:12
  • Updated question. I'm getting the error with mypy version `0.570`. Btw, I'm getting no python errors directly no matter if I apply the `metaclass=ABCMeta` or not. So `mypy` is the only tool that actually helps me to catch this error anyway. – Christoph Mar 15 '18 at 11:21
  • `mypy` and `python` do two very different things. `mypy` is a *static* analyzer, and is free to make the assumption that you forgot to use `ABCMeta` if `@abstractmethod` is present in the *source* of your code. `python` just interprets the code, and without `ABCMeta`, it has no reason to do anything with the list of methods populated by `@abstractmethod`. (Indeed, at *runtime* there is no evidence in the method itself that it *was* decorated.) – chepner Mar 15 '18 at 16:33
  • @chepner yes, that's true. It just happened that I noticed `mypy` catches the error without the `metaclass` being set and I didn't further check what `python` actually does. I just stopped there left wondering why `mypy` catches the error when I thought it shouldn't. Thanks for the background info! – Christoph Mar 16 '18 at 14:49

1 Answers1

4

Ok, turns out without metaclass=ABCMeta only mypy will catch the error whereas with the metaclass=ABCMeta both mypy and python will catch the error.

See:

from abc import abstractmethod

class C():
    @abstractmethod
    def my_abstract_method(self):
        print('foo')

class D(C):
    pass

x = C()
y = D()

$ mypy test.py 
test.py:13: error: Cannot instantiate abstract class 'C' with abstract attribute 'my_abstract_method'
test.py:15: error: Cannot instantiate abstract class 'D' with abstract attribute 'my_abstract_method'

but

$ python3 test.py
$

Whereas with that, python will catch the error as well.

from abc import ABCMeta, abstractmethod

class C(metaclass=ABCMeta):
    @abstractmethod
    def my_abstract_method(self):
        print('foo')

class D(C):
    pass

x = C()

y = D()


$ python3 test.py 
Traceback (most recent call last):
  File "test.py", line 11, in <module>
    x = C()
TypeError: Can't instantiate abstract class C with abstract methods my_abstract_method
Christoph
  • 26,519
  • 28
  • 95
  • 133