I'm having trouble with getting multiple dynamic inheritance to work. These examples make the most sense to me(here and here), but there's not enough code in one example for me to really understand what's going on and the other example doesn't seem to be working when I change it around for my needs (code below).
I'm creating a universal tool that works with multiple software packages. In one software, I need to inherit from 2 classes: 1 software specific API mixin, and 1 PySide class. In another software I only need to inherit from the 1 PySide class.
The least elegant solution that I can think of is to just create 2 separate classes (with all of the same methods) and call either one based on the software that's running. I have a feeling there's a better solution.
Here's what I'm working with:
## MainWindow.py
import os
from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
# Build class
def build_main_window(*arg):
class Build(arg):
def __init__(self):
super( Build, self ).__init__()
# ----- a bunch of methods
# Get software
software = os.getenv('SOFTWARE')
# Run tool
if software == 'maya':
build_main_window(maya_mixin_class, QtGui.QWidget)
if software == 'houdini':
build_main_window(QtGui.QWidget)
I'm currently getting this error:
# class Build(arg):
# TypeError: Error when calling the metaclass bases
# tuple() takes at most 1 argument (3 given) #
Thanks for any help!
EDIT:
## MainWindow.py
import os
# Build class
class BuildMixin():
def __init__(self):
super( BuildMixin, self ).__init__()
# ----- a bunch of methods
def build_main_window(*args):
return type('Build', (BuildMixin, QtGui.QWidget) + args, {})
# Get software
software = os.getenv('SOFTWARE')
# Run tool
if software == 'maya':
from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
Build = build_main_window(MayaQWidgetDockableMixin)
if software == 'houdini':
Build = build_main_window()
2 Answers 2
The error in your original code is caused by failing to use tuple expansion in the class definition. I would suggest simplifying your code to this:
# Get software
software = os.getenv('SOFTWARE')
BaseClasses = [QtGui.QWidget]
if software == 'maya':
from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
BaseClasses.insert(0, MayaQWidgetDockableMixin)
class Build(*BaseClasses):
def __init__(self, parent=None):
super(Build, self).__init__(parent)
UPDATE:
The above code will only work with Python 3, so it looks like a solution using type() will be needed for Python 2. From the other comments, it appears that the MayaQWidgetDockableMixin class may be a old-style class, so a solution like this may be necessary:
def BaseClass():
bases = [QtGui.QWidget]
if software == 'maya':
from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
class Mixin(MayaQWidgetDockableMixin, object): pass
bases.insert(0, Mixin)
return type('BuildBase', tuple(bases), {})
class Build(BaseClass()):
def __init__(self, parent=None):
super(Build, self).__init__(parent)
5 Comments
class Build(*BaseClasses):. I'm also getting an error in my IDE. Even directly copy and pasting your code causes errors to show up. I'm not familiar with this extension method, but it seems like the right one to go with if I can get it working. Any idea why I'm getting this error?arg is a tuple, you can't use a tuple as a base class.
Use type() to create a new class instead; it takes a class name, a tuple of base classes (can be empty) and the class body (a dictionary).
I'd keep the methods for your class in a mix-in method:
class BuildMixin():
def __init__(self):
super(BuildMixin, self).__init__()
# ----- a bunch of methods
def build_main_window(*arg):
return type('Build', (BuildMixin, QtGui.QWidget) + args, {})
if software == 'maya':
Build = build_main_window(maya_mixin_class)
if software == 'houdini':
Build = build_main_window()
Here, args is used as an additional set of classes to inherit from. The BuildMixin class provides all the real methods, so the third argument to type() is left empty (the generated Build class has an empty class body).
Since QtGui.QWidget is common between the two classes, I just moved that into the type() call.
2 Comments
# return type('Build', (BuildMixin, QtGui.QWidget) + args, {}) # TypeError: Invalid base class used in type Shiboken.ObjectType. PySide only support multiple inheritance from python new style class. I'm not exactly sure how this class is 'old' style? See my post above for what code I'm usingMayaQWidgetDockableMixin is an old-style class and you'd have to add object into the mix here.
argsitself. If you want dynamic multiple inheritance, usetype(name, bases, dct).