I'm trying to combine a class implementing an abc interface with another class.
Let's start with abc simple example:
import abc
class Interface(abc.ABC):
@abc.abstractmethod
def pure_virtual_func(self):
raise NotImplementedError
class Impl(Interface):
def __init__(self):
pass
impl = Impl()
This piece of code will fail when impl is created: Can't instantiate abstract class Impl with abstract methods pure_virtual_func. This is great, that's what you expect.
Now, when Impl needs to derive from another class:
import abc
from PySide6.QtWidgets import QApplication, QWidget
class Interface(abc.ABC):
@abc.abstractmethod
def pure_virtual_func(self):
raise NotImplementedError
class Impl(QWidget,Interface):
def __init__(self):
pass
app = QApplication()
impl = Impl()
You get the error: Error: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases.
According to some posts (Resolving metaclass conflicts and Abstract class inheriting from ABC and QMainWindow), it is recommended to do that:
import abc
from PySide6.QtWidgets import QApplication, QWidget
class Interface(abc.ABC):
@abc.abstractmethod
def pure_virtual_func(self):
raise NotImplementedError
class Meta(type(QWidget), type(Interface)):
pass
class Impl(QWidget, Interface, metaclass=Meta):
def __init__(self):
pass
app = QApplication()
impl = Impl()
OK, now the metaclass error is gone. But you don't get the error Can't instantiate abstract class Impl with abstract methods pure_virtual_func anymore, now the impl is simply created, and you'll get the NotImplementedError exception if pure_virtual_func is called.
The abc great feature detecting not implemented pure virtual method is gone, how can one derive from Interface and another class (QWidget in my exemple) and preserve not implemented pure virtual method detection?
There's many posts explaining how to make the code work with metaclass stuff, but I found none that preserves abc capability to detect not implemented pure virtual methods.
Short Description
The behavior you are observing is due to the implementation of your new Meta Class bypassing the abstract method checking behavior of
ABCMetametaclass for anyabcabstract class you use which is different from the metaclassQMetaObjectforQWidget.Recommendation Instead of using inheritance, you can try composition refactor your design to avoid using this method. Python allows multiple parents for a class which leads to the
diamond problemif not careful. But still if you desire to achieve the behavior requested you due to some constraints you can try the following.Code
Using the inspect module we explicitly check for all memebers of the class if they are an abstract method. If
Truewe throw an exception similar to theabcmodule.