diff options
| author | Christian Tismer <tismer@stackless.com> | 2021-05-16 12:24:00 +0200 |
|---|---|---|
| committer | Christian Tismer <tismer@stackless.com> | 2023-03-21 08:49:56 +0100 |
| commit | e8095467f7d0332cc0987e7c541de9906e19fece (patch) | |
| tree | c414491f86f34308a051bdb781581b23431a4e20 /sources/pyside6 | |
| parent | 18812159a8cd5295ac8d51e37f9021ad21434b90 (diff) | |
Implement multiple inheritance correctly, compatible version
PySide does not implement multiple inheritance.
Please see "About Multiple Inheritance in Python" at the issue.
This patch just supports the `__init__` call.
A more consequent implementation will follow that
supports multiple inheritance with every method.
[ChangeLog][pyside6] Cooperative multiple inheritance is now
implemented for all __init__ methods.
Fixes: PYSIDE-1564
Change-Id: I8df805d22c2052c3a9747420a86341f64e29a5ad
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'sources/pyside6')
| -rw-r--r-- | sources/pyside6/libpyside/pyside.cpp | 7 | ||||
| -rw-r--r-- | sources/pyside6/libpyside/pysideqobject.h | 3 | ||||
| -rw-r--r-- | sources/pyside6/tests/pysidetest/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | sources/pyside6/tests/pysidetest/multiple_inheritance_test.py | 127 |
4 files changed, 136 insertions, 2 deletions
diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp index 42b7725cc..29a3d2884 100644 --- a/sources/pyside6/libpyside/pyside.cpp +++ b/sources/pyside6/libpyside/pyside.cpp @@ -299,7 +299,8 @@ static bool _setProperty(PyObject *qObj, PyObject *name, PyObject *value, bool * return true; } -bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds) +bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, + PyObject *kwds, bool allowErrors) { PyObject *key, *value; @@ -331,6 +332,10 @@ bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds return false; } } + if (allowErrors) { + PyErr_Clear(); + continue; + } if (!accept) { PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal", propName.constData()); diff --git a/sources/pyside6/libpyside/pysideqobject.h b/sources/pyside6/libpyside/pysideqobject.h index 2bd9b74ca..07453bc12 100644 --- a/sources/pyside6/libpyside/pysideqobject.h +++ b/sources/pyside6/libpyside/pysideqobject.h @@ -22,7 +22,8 @@ namespace PySide /// \param metaObj QMetaObject of \p qObj. /// \param kwds key->value dictonary. /// \return True if everything goes well, false with a Python error set otherwise. -PYSIDE_API bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, PyObject *kwds); +PYSIDE_API bool fillQtProperties(PyObject *qObj, const QMetaObject *metaObj, + PyObject *kwds, bool allowErrors); PYSIDE_API void initDynamicMetaObject(PyTypeObject *type, const QMetaObject *base, std::size_t cppObjSize); diff --git a/sources/pyside6/tests/pysidetest/CMakeLists.txt b/sources/pyside6/tests/pysidetest/CMakeLists.txt index 797b72c45..f64cea904 100644 --- a/sources/pyside6/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside6/tests/pysidetest/CMakeLists.txt @@ -145,6 +145,7 @@ PYSIDE_TEST(iterable_test.py) PYSIDE_TEST(list_signal_test.py) PYSIDE_TEST(mixin_signal_slots_test.py) PYSIDE_TEST(modelview_test.py) +PYSIDE_TEST(multiple_inheritance_test.py) PYSIDE_TEST(new_inherited_functions_test.py) PYSIDE_TEST(notify_id.py) PYSIDE_TEST(properties_test.py) diff --git a/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py b/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py new file mode 100644 index 000000000..6e48ac735 --- /dev/null +++ b/sources/pyside6/tests/pysidetest/multiple_inheritance_test.py @@ -0,0 +1,127 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from init_paths import init_test_paths +init_test_paths(False) + +from helper.usesqapplication import UsesQApplication +from PySide6 import QtCore, QtGui, QtWidgets + + +def xprint(*args, **kw): + if "-v" in sys.argv: + print(*args, **kw) + +# This is the original testcase of PYSIDE-1564 +class Age(object): + def __init__(self, age=0, **kwds): + super().__init__(**kwds) + + self.age = age + +class Person(QtCore.QObject, Age): + def __init__(self, name, **kwds): + super().__init__(**kwds) + + self.name = name + + +class OriginalMultipleInheritanceTest(unittest.TestCase): + + def testIt(self): + xprint() + p = Person("Joe", age=38) + xprint(f"p.age = {p.age}") + # This would crash if MI does not work. + +# More tests follow: + +# mro ('C', 'A', 'QObject', 'Object', 'B', 'object') +class A(QtCore.QObject): + def __init__(self, anna=77, **kw): + xprint(f'A: before init kw = {kw}') + super().__init__(**kw) + xprint('A: after init') + +class B: + def __init__(self, otto=6, age=7, **kw): + xprint(f'B: before init kw = {kw}') + if "killme" in kw: + raise AssertionError("asdf") + super().__init__(**kw) + self.age = age + xprint('B: after init') + +class C(A, B): + def __init__(self, **kw): + xprint(f'C: before init kw = {kw}') + super().__init__(**kw) + xprint('C: after init') + +# 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}') + super().__init__(**kw) + xprint('D: after init') + +class E: + def __init__(self, age=7, **kw): + xprint(f'E: before init kw = {kw}') + super().__init__(**kw) + self.age = age + xprint('E: after init') + +class F(D, E, QtWidgets.QLabel): + def __init__(self, **kw): + xprint(f'F: before init kw = {kw}') + super().__init__(**kw) + xprint('F: after init') + +# 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 + +class H: + def __init__(self, age=7, **kw): + xprint(f'H: before init kw = {kw}') + super().__init__(**kw) + self.age = age + xprint('H: after init') + +class I(G, H, QtWidgets.QLabel): + pass + + +class AdditionalMultipleInheritanceTest(UsesQApplication): + + def testABC(self): + xprint() + res = C(otto=3, anna=5) + self.assertEqual(res.age, 7) + xprint() + with self.assertRaises(AssertionError): + res=C(killme=42) + xprint() + + def testDEF(self): + xprint() + res = F(anna=5) + self.assertEqual(res.age, 7) + xprint() + + def testGHI(self): + xprint() + res = I(age=7) + self.assertEqual(res.age, 7) + xprint() + +if __name__ == "__main__": + unittest.main() |
