Voici ce que j'ai trouvé : si vous définissez l'attribut __abstractmethods__
comme un ensemble vide, vous pourrez instancier une classe abstraite. Ce comportement est spécifié dans PEP 3119 :
Si l'ensemble __abstractmethods__
résultant n'est pas vide, la classe est considérée comme abstraite, et toute tentative de l'instancier lèvera une TypeError.
Vous avez simplement besoin de vider cet attribut pendant les tests.
>>> import abc
>>> class A(metaclass = abc.ABCMeta):
... @abc.abstractmethod
... def foo(self): pass
Vous ne pouvez pas instancier A :
>>> A()
Traceback (most recent call last):
TypeError: Can't instantiate abstract class A with abstract methods foo
Si vous substituez __abstractmethods__
vous pouvez le faire :
>>> A.__abstractmethods__=set()
>>> A() #doctest: +ELLIPSIS
<....A object at 0x...>
Cela fonctionne dans les deux sens :
>>> class B(object): pass
>>> B() #doctest: +ELLIPSIS
<....B object at 0x...>
>>> B.__abstractmethods__={"foo"}
>>> B()
Traceback (most recent call last):
TypeError: Can't instantiate abstract class B with abstract methods foo
Vous pouvez également utiliser unittest.mock
(à partir de 3.3) pour substituer temporairement le comportement ABC.
>>> class A(metaclass = abc.ABCMeta):
... @abc.abstractmethod
... def foo(self): pass
>>> from unittest.mock import patch
>>> p = patch.multiple(A, __abstractmethods__=set())
>>> p.start()
{}
>>> A() #doctest: +ELLIPSIS
<....A object at 0x...>
>>> p.stop()
>>> A()
Traceback (most recent call last):
TypeError: Can't instantiate abstract class A with abstract methods foo