aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2024-03-27 18:06:28 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-03-28 10:46:47 +0000
commit706260d752694232e53fd9a87b2c096fdc3e83e8 (patch)
tree977c3ee39338ea3a35cb87be32a4ab7041c46f08
parent0952bc19784d6b1f762f93eb50d8f70c71031fe2 (diff)
Implement multiple inheritance correctly, 2nd. amendment
When a Python class does _not_ implement __init__, then we might get the default of object.__init__, which must be skipped like the object class alone. Change-Id: I0416c97854e8d1c9edf0b9ac44d3df58223fef84 Fixes: PYSIDE-2654 Task-number: PYSIDE-2294 Pick-to: 6.5 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io> (cherry picked from commit 7b709cf594d9c308b57eacd784845beff9c72c2f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> (cherry picked from commit a5a2e97aaaf7b5c2ea7d9547cc0fdfbc9b09c97a)
-rw-r--r--sources/pyside6/tests/pysidetest/multiple_inheritance_test.py40
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.cpp6
2 files changed, 41 insertions, 5 deletions
diff --git a/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py b/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py
index fe8e14f9f..49550ba55 100644
--- a/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py
+++ b/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py
@@ -12,7 +12,7 @@ init_test_paths(False)
from helper.usesqapplication import UsesQApplication
from PySide6 import QtCore, QtGui, QtWidgets
-from PySide6.QtWidgets import QMainWindow, QLabel
+from PySide6.QtWidgets import QMainWindow, QLabel, QWidget
def xprint(*args, **kw):
@@ -71,7 +71,8 @@ class C(A, B):
xprint('C: after init')
-# mro ('F', 'D', 'QCursor', 'E', 'QLabel', 'QFrame', 'QWidget', 'QObject', 'QPaintDevice', 'Object', 'object')
+# mro ('F', 'D', 'QCursor', 'E', 'QLabel', 'QFrame', 'QWidget', 'QObject',
+# 'QPaintDevice', 'Object', 'object')
class D(QtGui.QCursor):
def __init__(self, anna=77, **kw):
xprint(f'D: before init kw = {kw}')
@@ -94,7 +95,8 @@ class F(D, E, QtWidgets.QLabel):
xprint('F: after init')
-# mro ('I', 'G', 'QTextDocument', 'H', 'QLabel', 'QFrame', 'QWidget', 'QObject', 'QPaintDevice', 'Object', 'object')
+# mro ('I', 'G', 'QTextDocument', 'H', 'QLabel', 'QFrame', 'QWidget', 'QObject',
+# 'QPaintDevice', 'Object', 'object')
# Similar, but this time we want to reach `H` without support from `super`.
class G(QtGui.QTextDocument):
pass
@@ -108,7 +110,7 @@ class H:
xprint('H: after init')
-class I(G, H, QtWidgets.QLabel):
+class II(G, H, QtWidgets.QLabel):
pass
@@ -145,7 +147,7 @@ class AdditionalMultipleInheritanceTest(UsesQApplication):
def testGHI(self):
xprint()
- res = I(age=7)
+ res = II(age=7)
self.assertEqual(res.age, 7)
xprint()
@@ -155,5 +157,33 @@ class AdditionalMultipleInheritanceTest(UsesQApplication):
MainWindow()
+# PYSIDE-2654: Additional missing init test.
+# This must work if no __init__ is defined (Ui_Form)
+class Ui_Form(object):
+ pass
+
+
+class Mixin:
+ def __init__(self, **kwargs) -> None:
+ super().__init__(**kwargs)
+
+
+class Card(Mixin, QWidget):
+ def __init__(self, parent=None) -> None:
+ super().__init__(parent=parent)
+
+
+class Demo(Card, Ui_Form):
+ def __init__(self) -> None:
+ super().__init__()
+
+
+class MissingInitFunctionTest(UsesQApplication):
+ def testMissing(self):
+ Demo()
+ # Tests if this works. Would crash without the extra
+ # check for object.__init__
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp
index a9b87f7f4..a0acc4e4b 100644
--- a/sources/shiboken6/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken6/libshiboken/bindingmanager.cpp
@@ -408,6 +408,8 @@ bool callInheritedInit(PyObject *self, PyObject *args, PyObject *kwds,
using Shiboken::AutoDecRef;
static PyObject *const _init = String::createStaticString("__init__");
+ static PyObject *objectInit =
+ PyObject_GetAttr(reinterpret_cast<PyObject *>(&PyBaseObject_Type), _init);
// A native C++ self cannot have multiple inheritance.
if (!Object::isUserType(self))
@@ -441,6 +443,10 @@ bool callInheritedInit(PyObject *self, PyObject *args, PyObject *kwds,
if (subType == &PyBaseObject_Type)
return false;
AutoDecRef func(PyObject_GetAttr(obSubType, _init));
+ // PYSIDE-2654: If this has no implementation then we get object.__init__
+ // but that is the same case like above.
+ if (func == objectInit)
+ return false;
// PYSIDE-2294: We need to explicitly ignore positional args in a mixin class.
SBK_UNUSED(args);
AutoDecRef newArgs(PyTuple_New(1));