I have a base class from which other classes should inherit:
class AppToolbar(wx.ToolBar):
''' Base class for the Canary toolbars '''
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ... a few common implementation details that work as expected...
self._PopulateToolbar()
self.Realize()
The base class does not (and cannot) implement _PopulateToolbar()
; it should be an abstract method. As such, I figured using abc
was a good plan, so I tried this:
class AppToolbar(wx.ToolBar, metaclass=abc.ABCMeta):
# ... as above, but with the following added
@abc.abstractmethod
def _PopulateToolbar():
pass
Perhaps unsurprisingly, attempting to run this led to TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
. I thought, "Oh, right, I'll just use a mixin":
class PopulateToolbarMixin(metaclass=ABCMeta):
@abstractmethod
def _PopulateToolbar(self):
pass
PopulateToolbarMixin.register(wx.ToolBar)
PopulateToolbarMixin.register(AppToolbar)
No change: still the same TypeError
message. I suspect I'm missing something obvious with the use of ABCMeta
here; this doesn't look like an error specific to wxPython. What am I doing wrong? Is there a better way to approach the same issue?
Edit: it has been pointed out to me in a conversation with a colleague that one cannot mix metaclasses. Since wx.ToolBar
apparently derives from sip.wrappertype
, it looks like there is no way to do this. What is another, still Pythonic way to handle the "abstract method" approach here?
In your first example, where you inherit from wx.ToolBar and abc.ABCMeta, you don't want AppToolbar to be a subclass of abc.ABCMeta, you want AppToolbar to be an instance of it. Try this:
class AppToolbar(wx.ToolBar, metaclass=abc.ABCMeta):
# ... as above, but with the following added
@abc.abstractmethod
def _PopulateToolbar():
pass
Though looking at this a bit closer, it seems that you can't define a subclass of wx.Toolbar with abc.ABCMeta as its metaclass, as wx.Toolbar is an instance of a metaclass other than bultins.type. You can, however, get abstract-like behavior out of AppToolbar._PopulateToolbar:
class AppToolbar(wx.ToolBar):
def _PopulateToolbar():
''' This is an abstract method; subclasses must override it. '''
raise NotImplementedError('Abstract method "_PopulateToolbar" must be overridden before it can be called.')