diff options
author | Christian Tismer <tismer@stackless.com> | 2023-10-26 23:32:10 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-11-14 16:23:33 +0000 |
commit | a2819f087892a1b82677ba1dc22dedee2d537efc (patch) | |
tree | 54f0055153f920ea1c991929fae8c8886c619f27 | |
parent | 2b560b5a096993898da22a09ef143c9e24dbcb4c (diff) |
Shiboken: Fix subtle bug caused by PyPy support and "bug_825"
When implementing PyPy support, all Shiboken types lost their
hidden extra fields, because they were replaced by shadow dicts.
This creates a problem with multiple inheritance.
In Python < 3.12, the decision which base type will create the
instance is driven simply by the size of the type. In
class MetaC(MetaA, MetaB):
pass
when MetaA is derived from type and MetaB is derived from
SbkObjectType, MetaA is not the type that should win.
Fixed by simply adding 1 to the default size of PyType_Type.
Caused by bug_825 corrected version.
The old test is retained as bug_825_old.py .
NOTE: This touches a Python 3.8 bug that was fixed in 3.9.12
and 3.10.4 - unfortunately CI Python is older in all cases.
Task-number: PYSIDE-2230
Change-Id: I6e82cafb83c8351bbbeafcc80e11d5e45568f73d
Pick-to: 6.5 6.2
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
(cherry picked from commit 9557565b48b2a72b7697443930234f9f92c17781)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | build_history/blacklist.txt | 5 | ||||
-rw-r--r-- | sources/pyside6/tests/QtQml/CMakeLists.txt | 1 | ||||
-rw-r--r-- | sources/pyside6/tests/QtQml/bug_825.py | 14 | ||||
-rw-r--r-- | sources/pyside6/tests/QtQml/bug_825_old.py | 80 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/basewrapper.cpp | 13 |
5 files changed, 104 insertions, 9 deletions
diff --git a/build_history/blacklist.txt b/build_history/blacklist.txt index cb9b1c500..60cc3f955 100644 --- a/build_history/blacklist.txt +++ b/build_history/blacklist.txt @@ -43,7 +43,10 @@ darwin ci [QtAsyncio::qasyncio_test_chain] win32 - +[QtQml::bug_825] + py3.8 # bug in typeobject::type_mro_modified, fix in 3.9 + py3.9 # fixed in 3.9.12 + py3.10 # fixed in 3.10.4 # PYSIDE-535: These errors are still present. Please try to remove one :) [sample::mixed_mi] pypy diff --git a/sources/pyside6/tests/QtQml/CMakeLists.txt b/sources/pyside6/tests/QtQml/CMakeLists.txt index c24beb35a..720f0ef99 100644 --- a/sources/pyside6/tests/QtQml/CMakeLists.txt +++ b/sources/pyside6/tests/QtQml/CMakeLists.txt @@ -6,6 +6,7 @@ PYSIDE_TEST(bug_456.py) PYSIDE_TEST(bug_557.py) PYSIDE_TEST(bug_726.py) PYSIDE_TEST(bug_814.py) +PYSIDE_TEST(bug_825_old.py) PYSIDE_TEST(bug_825.py) PYSIDE_TEST(bug_847.py) PYSIDE_TEST(bug_915.py) diff --git a/sources/pyside6/tests/QtQml/bug_825.py b/sources/pyside6/tests/QtQml/bug_825.py index 9771d0634..1d9b82d16 100644 --- a/sources/pyside6/tests/QtQml/bug_825.py +++ b/sources/pyside6/tests/QtQml/bug_825.py @@ -1,6 +1,11 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +""" +This is the corrected version for Python 3. +Unfortunately, this touches a Python 3.8 error that was fixed late. +""" + import os import sys import unittest @@ -25,9 +30,8 @@ class MetaA(type): pass -class A(object): - __metaclass__ = MetaA - +class A(object, metaclass=MetaA): + pass MetaB = type(QQuickPaintedItem) B = QQuickPaintedItem @@ -37,8 +41,8 @@ class MetaC(MetaA, MetaB): pass -class C(A, B): - __metaclass__ = MetaC +class C(A, B, metaclass=MetaC): + pass class Bug825 (C): diff --git a/sources/pyside6/tests/QtQml/bug_825_old.py b/sources/pyside6/tests/QtQml/bug_825_old.py new file mode 100644 index 000000000..c44fa75f4 --- /dev/null +++ b/sources/pyside6/tests/QtQml/bug_825_old.py @@ -0,0 +1,80 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +""" +This is the now incorrect old version from Python 2. +It happens to work in another way and will be retained. +""" + +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.helper import quickview_errorstring + +from PySide6.QtCore import Qt, QUrl, QTimer +from PySide6.QtGui import QGuiApplication, QPen +from PySide6.QtWidgets import QGraphicsItem +from PySide6.QtQml import qmlRegisterType +from PySide6.QtQuick import QQuickView, QQuickItem, QQuickPaintedItem + +paintCalled = False + + +class MetaA(type): + pass + + +class A(object): + __metaclass__ = MetaA + + +MetaB = type(QQuickPaintedItem) +B = QQuickPaintedItem + + +class MetaC(MetaA, MetaB): + pass + + +class C(A, B): + __metaclass__ = MetaC + + +class Bug825 (C): + def __init__(self, parent=None): + QQuickPaintedItem.__init__(self, parent) + + def paint(self, painter): + global paintCalled + pen = QPen(Qt.black, 2) + painter.setPen(pen) + painter.drawPie(self.boundingRect(), 0, 128) + paintCalled = True + + +class TestBug825 (unittest.TestCase): + def testIt(self): + global paintCalled + app = QGuiApplication([]) + qmlRegisterType(Bug825, 'bugs', 1, 0, 'Bug825') + self.assertRaises(TypeError, qmlRegisterType, A, 'bugs', 1, 0, 'A') + + view = QQuickView() + file = Path(__file__).resolve().parent / 'bug_825.qml' + self.assertTrue(file.is_file()) + view.setSource(QUrl.fromLocalFile(file)) + self.assertTrue(view.rootObject(), quickview_errorstring(view)) + view.show() + QTimer.singleShot(250, view.close) + app.exec() + self.assertTrue(paintCalled) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp index d33f06431..828c54a89 100644 --- a/sources/shiboken6/libshiboken/basewrapper.cpp +++ b/sources/shiboken6/libshiboken/basewrapper.cpp @@ -139,11 +139,18 @@ static PyTypeObject *createObjectTypeType() }; // PYSIDE-535: The tp_itemsize field is inherited and does not need to be set. - // In PyPy, it _must_ not be set, because it would have the meaning that a - // `__len__` field must be defined. Not doing so creates a hard-to-find crash. + // In PyPy, it _must_ not be set, because it would have the meanin + // that a `__len__` field must be defined. Not doing so creates + // a hard-to-find crash. + // + // PYSIDE-2230: In Python < 3.12, the decision which base class should create + // the instance is arbitrarily drawn by the size of the type. + // Ignoring this creates a bug in the new version of bug_825 that + // selects the wrong metatype. + // PyType_Spec SbkObjectType_Type_spec = { "1:Shiboken.ObjectType", - 0, + static_cast<int>(PyType_Type.tp_basicsize) + 1, // see above 0, // sizeof(PyMemberDef), not for PyPy without a __len__ defined Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, SbkObjectType_Type_slots, |