Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added PySide6 shiboken6 support #376

Merged
merged 10 commits into from
Feb 20, 2024
130 changes: 121 additions & 9 deletions Qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
DOCUMENTATION
Qt.py was born in the film and visual effects industry to address
the growing need for the development of software capable of running
with more than one flavour of the Qt bindings for Python - PySide,
PySide2, PyQt4 and PyQt5.
with more than one flavour of the Qt bindings for Python.

Supported Binding: PySide, PySide2, PySide6, PyQt4, PyQt5

1. Build for one, run with all
2. Explicit is better than implicit
3. Support co-existence

Default resolution order:
- PySide6
- PySide2
- PyQt5
- PySide
Expand Down Expand Up @@ -215,6 +217,7 @@
],
"QtGui": [
"QAbstractTextDocumentLayout",
"QAction",
"QActionEvent",
"QBitmap",
"QBrush",
Expand Down Expand Up @@ -442,7 +445,6 @@
"QAbstractScrollArea",
"QAbstractSlider",
"QAbstractSpinBox",
"QAction",
"QActionGroup",
"QApplication",
"QBoxLayout",
Expand Down Expand Up @@ -550,7 +552,6 @@
"QRubberBand",
"QScrollArea",
"QScrollBar",
"QShortcut",
"QSizeGrip",
"QSizePolicy",
"QSlider",
Expand Down Expand Up @@ -730,12 +731,14 @@ def messageOutputHandler(*args):
passObject = messageOutputHandler if handler else handler
if Qt.IsPySide or Qt.IsPyQt4:
return Qt._QtCore.qInstallMsgHandler(passObject)
elif Qt.IsPySide2 or Qt.IsPyQt5:
elif Qt.IsPySide2 or Qt.IsPyQt5 or Qt.IsPySide6:
return Qt._QtCore.qInstallMessageHandler(passObject)


def _getcpppointer(object):
if hasattr(Qt, "_shiboken2"):
if hasattr(Qt, "_shiboken6"):
return getattr(Qt, "_shiboken6").getCppPointer(object)[0]
elif hasattr(Qt, "_shiboken2"):
return getattr(Qt, "_shiboken2").getCppPointer(object)[0]
elif hasattr(Qt, "_shiboken"):
return getattr(Qt, "_shiboken").getCppPointer(object)[0]
Expand Down Expand Up @@ -773,6 +776,8 @@ def _wrapinstance(ptr, base=None):
func = getattr(Qt, "_sip").wrapinstance
elif Qt.IsPySide2:
func = getattr(Qt, "_shiboken2").wrapInstance
elif Qt.IsPySide6:
func = getattr(Qt, "_shiboken6").wrapInstance
elif Qt.IsPySide:
func = getattr(Qt, "_shiboken").wrapInstance
else:
Expand Down Expand Up @@ -812,7 +817,10 @@ def _isvalid(object):
object (QObject): QObject to check the validity of.

"""
if hasattr(Qt, "_shiboken2"):
if hasattr(Qt, "_shiboken6"):
return getattr(Qt, "_shiboken6").isValid(object)

elif hasattr(Qt, "_shiboken2"):
return getattr(Qt, "_shiboken2").isValid(object)

elif hasattr(Qt, "_shiboken"):
Expand Down Expand Up @@ -1014,9 +1022,41 @@ def createWidget(self, class_name, parent=None, name=""):

"""
_misplaced_members = {
"PySide6": {
"QtGui.QShortcut": "QtWidgets.QShortcut",
"QtCore.QStringListModel": "QtCore.QStringListModel",
"QtGui.QStringListModel": "QtCore.QStringListModel",
"QtGui.QAction": "QtWidgets.QAction",
"QtCore.Property": "QtCore.Property",
"QtCore.Signal": "QtCore.Signal",
"QtCore.Slot": "QtCore.Slot",
"QtCore.QAbstractProxyModel": "QtCore.QAbstractProxyModel",
"QtCore.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel",
"QtCore.QItemSelection": "QtCore.QItemSelection",
"QtCore.QItemSelectionModel": "QtCore.QItemSelectionModel",
"QtCore.QItemSelectionRange": "QtCore.QItemSelectionRange",
"QtUiTools.QUiLoader": ["QtCompat.loadUi", _loadUi],
"shiboken6.wrapInstance": ["QtCompat.wrapInstance", _wrapinstance],
"shiboken6.getCppPointer": ["QtCompat.getCppPointer", _getcpppointer],
"shiboken6.isValid": ["QtCompat.isValid", _isvalid],
"QtWidgets.qApp": "QtWidgets.QApplication.instance()",
"QtCore.QCoreApplication.translate": [
"QtCompat.translate", _translate
],
"QtWidgets.QApplication.translate": [
"QtCompat.translate", _translate
],
"QtCore.qInstallMessageHandler": [
"QtCompat.qInstallMessageHandler", _qInstallMessageHandler
],
"QtWidgets.QStyleOptionViewItem": "QtCompat.QStyleOptionViewItemV4",
"QtMultimedia.QSound": "QtMultimedia.QSound",
},
"PySide2": {
"QtWidgets.QShortcut": "QtWidgets.QShortcut",
"QtCore.QStringListModel": "QtCore.QStringListModel",
"QtGui.QStringListModel": "QtCore.QStringListModel",
"QtWidgets.QAction": "QtWidgets.QAction",
"QtCore.Property": "QtCore.Property",
"QtCore.Signal": "QtCore.Signal",
"QtCore.Slot": "QtCore.Slot",
Expand All @@ -1043,6 +1083,8 @@ def createWidget(self, class_name, parent=None, name=""):
"QtMultimedia.QSound": "QtMultimedia.QSound",
},
"PyQt5": {
"QtWidgets.QShortcut": "QtWidgets.QShortcut",
"QtWidgets.QAction": "QtWidgets.QAction",
"QtCore.pyqtProperty": "QtCore.Property",
"QtCore.pyqtSignal": "QtCore.Signal",
"QtCore.pyqtSlot": "QtCore.Slot",
Expand Down Expand Up @@ -1070,6 +1112,8 @@ def createWidget(self, class_name, parent=None, name=""):
"QtMultimedia.QSound": "QtMultimedia.QSound",
},
"PySide": {
"QtWidgets.QShortcut": "QtWidgets.QShortcut",
"QtWidgets.QAction": "QtWidgets.QAction",
"QtGui.QAbstractProxyModel": "QtCore.QAbstractProxyModel",
"QtGui.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel",
"QtGui.QStringListModel": "QtCore.QStringListModel",
Expand Down Expand Up @@ -1105,6 +1149,8 @@ def createWidget(self, class_name, parent=None, name=""):
"QtGui.QSound": "QtMultimedia.QSound",
},
"PyQt4": {
"QtWidgets.QShortcut": "QtWidgets.QShortcut",
"QtWidgets.QAction": "QtWidgets.QAction",
"QtGui.QAbstractProxyModel": "QtCore.QAbstractProxyModel",
"QtGui.QSortFilterProxyModel": "QtCore.QSortFilterProxyModel",
"QtGui.QItemSelection": "QtCore.QItemSelection",
Expand Down Expand Up @@ -1157,6 +1203,26 @@ def createWidget(self, class_name, parent=None, name=""):
}
"""
_compatibility_members = {
"PySide6": {
"QWidget": {
"grab": "QtWidgets.QWidget.grab",
},
"QHeaderView": {
"sectionsClickable": "QtWidgets.QHeaderView.sectionsClickable",
"setSectionsClickable":
"QtWidgets.QHeaderView.setSectionsClickable",
"sectionResizeMode": "QtWidgets.QHeaderView.sectionResizeMode",
"setSectionResizeMode":
"QtWidgets.QHeaderView.setSectionResizeMode",
"sectionsMovable": "QtWidgets.QHeaderView.sectionsMovable",
"setSectionsMovable": "QtWidgets.QHeaderView.setSectionsMovable",
},
"QFileDialog": {
"getOpenFileName": "QtWidgets.QFileDialog.getOpenFileName",
"getOpenFileNames": "QtWidgets.QFileDialog.getOpenFileNames",
"getSaveFileName": "QtWidgets.QFileDialog.getSaveFileName",
},
},
"PySide2": {
"QWidget": {
"grab": "QtWidgets.QWidget.grab",
Expand Down Expand Up @@ -1435,6 +1501,50 @@ def _build_compatibility_members(binding, decorators=None):
setattr(Qt.QtCompat, classname, compat_class)


def _pyside6():
zoshua marked this conversation as resolved.
Show resolved Hide resolved
"""Initialise PySide6

These functions serve to test the existence of a binding
along with set it up in such a way that it aligns with
the final step; adding members from the original binding
to Qt.py

"""

import PySide6 as module
extras = ["QtUiTools"]
try:
import shiboken6
extras.append("shiboken6")
except ImportError as e:
print("ImportError: %s" % e)

_setup(module, extras)
Qt.__binding_version__ = module.__version__

if hasattr(Qt, "_shiboken6"):
Qt.QtCompat.wrapInstance = _wrapinstance
Qt.QtCompat.getCppPointer = _getcpppointer
Qt.QtCompat.delete = shiboken6.delete

if hasattr(Qt, "_QtUiTools"):
Qt.QtCompat.loadUi = _loadUi

if hasattr(Qt, "_QtCore"):
Qt.__qt_version__ = Qt._QtCore.qVersion()
Qt.QtCompat.dataChanged = (
lambda self, topleft, bottomright, roles=None:
self.dataChanged.emit(topleft, bottomright, roles or [])
)

if hasattr(Qt, "_QtWidgets"):
Qt.QtCompat.setSectionResizeMode = \
Qt._QtWidgets.QHeaderView.setSectionResizeMode

_reassign_misplaced_members("PySide6")
_build_compatibility_members("PySide6")


def _pyside2():
"""Initialise PySide2

Expand Down Expand Up @@ -1821,7 +1931,7 @@ def __call__(self, *a, **kw):

def _install():
# Default order (customize order and content via QT_PREFERRED_BINDING)
default_order = ("PySide2", "PyQt5", "PySide", "PyQt4")
default_order = ("PySide6", "PySide2", "PyQt5", "PySide", "PyQt4")
preferred_order = None
if QT_PREFERRED_BINDING_JSON:
# A per-vendor preferred binding customization was defined
Expand Down Expand Up @@ -1854,6 +1964,7 @@ def _install():
order = preferred_order or default_order

available = {
"PySide6": _pyside6,
"PySide2": _pyside2,
"PyQt5": _pyqt5,
"PySide": _pyside,
Expand Down Expand Up @@ -1938,6 +2049,7 @@ def _install():
_install()

# Setup Binding Enum states
Qt.IsPySide6 = Qt.__binding__ == "PySide6"
Qt.IsPySide2 = Qt.__binding__ == 'PySide2'
Qt.IsPyQt5 = Qt.__binding__ == 'PyQt5'
Qt.IsPySide = Qt.__binding__ == 'PySide'
Expand Down Expand Up @@ -2050,4 +2162,4 @@ def _install():
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
zoshua marked this conversation as resolved.
Show resolved Hide resolved