Description
I believe this is fair to categorize as a bug, it certainly gives a worse Python wrapping experience compared to PyQt. The issue below demonstrates a particular problem when trying to set one widget as a parent of another but it exposes a more general problem of interoperability.
Specifically, when embedding Python in a C++ application, if that application has Qt widgets the QWidget base class of those widgets is not the same as the base class of widgets created by Python.
I am not providing any source code here because the issue can be replicated with the scriptedapplication example code provided with PySide2. To follow along, you simply need to build that application and then post and execute the following snippets in the text editor window.
First some setup:
from PySide2 import QtWidgets def get_menu_bar(): """Returns the only QMenuBar in the application.""" for w in QtWidgets.QApplication.instance().allWidgets(): if w.metaObject().className() == 'QMenuBar': return w # create a new menu menu = QtWidgets.QMenu() # retrieve the menubar menuBar = get_menu_bar()
Then you can try the following:
menu.setParent(menuBar)
You will then hit this traceback:
Traceback (most recent call last): File "<string>", line 8, in <module> TypeError: 'PySide2.QtWidgets.QWidget.setParent' called with wrong argument types: PySide2.QtWidgets.QWidget.setParent(QMenuBar) Supported signatures: PySide2.QtWidgets.QWidget.setParent(PySide2.QtWidgets.QWidget) PySide2.QtWidgets.QWidget.setParent(PySide2.QtWidgets.QWidget, PySide2.QtCore.Qt.WindowFlags)
You will notice that you do not get a traceback if you do the following instead:
from shiboken2 import wrapInstance, getCppPointer menu.setParent(wrapInstance(getCppPointer(menuBar)[0], QtWidgets.QMenuBar))
In tracking the above error down the issue is that isinstance(menuBar, QtWidgets.QWidget) is failing. The reason for that is that although menuBar inherits from QtWidgets.QWidget it is a different QtWidgets.QWidget that the one Python expects.
Here is some more Python code to run to show the issue in more detail:
print "menuBar", getattr(menuBar.__class__, '__bases__', None), issubclass(menuBar.__class__, QtWidgets.QWidget) print "menu", getattr(menu.__class__, '__bases__', None), issubclass(menu.__class__, QtWidgets.QWidget) print "id of first base class of menuBar", id(menuBar.__class__.__bases__[0]) print "id of first base class of menu", id(menu.__class__.__bases__[0]) print "id of QtWidgets.QWidget", id(QtWidgets.QWidget)
This produces the following output:
menuBar (<class 'PySide2.QtWidgets.QWidget'>,) False menu (<class 'PySide2.QtWidgets.QWidget'>,) True id of first base class of menuBar 36258560 id of first base class of menu 43100800 id of QtWidgets.QWidget 43100800
This shows you the root issue that the id of the two base classes are different and therefore are not equal causing isinstance to fail.
Ideally there would be only 1 instance of the PySide2.QtWidgets.QWidget class at runtime.
Thank you for reading !
Attachments
Issue Links
- duplicates
-
PYSIDE-1214 Type issues when returning C++ classes which subclass Qt types
- Closed