Question

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?

Was it helpful?

Solution

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.')
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top