diff options
author | Christian Tismer <tismer@stackless.com> | 2022-11-16 14:58:28 +0100 |
---|---|---|
committer | Christian Tismer <tismer@stackless.com> | 2022-11-24 13:20:36 +0100 |
commit | a4329741e960bc9f9efc690ba849c55b32496191 (patch) | |
tree | 008be57f877637de1e14ab38d067666b3542fa6e | |
parent | c4995ad3e0b3c089e033391e73e3b944de49263a (diff) |
__feature__: Fix true_property inheritance
The wrapping process creates wrapper functions for all C functions,
also for those which are meant as virtual functions promoting an
inherited function.
Because properties appear as such additional functions, we need to
convert not only according to the property strings, but also use
the mro to reach the extra functions indirectly.
[ChangeLog][PySide6] true_property was fixed to work with inherited
properties as well.
Change-Id: I176a30df77f550504f3aaf71e0c20de3e0707792
Fixes: PYSIDE-2042
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
(cherry picked from commit 2b14cba81265bbeb31b35dc4e04ccd3f6e29c4ee)
-rw-r--r-- | sources/pyside6/libpyside/feature_select.cpp | 30 | ||||
-rw-r--r-- | sources/pyside6/tests/pysidetest/CMakeLists.txt | 1 | ||||
-rw-r--r-- | sources/pyside6/tests/pysidetest/true_property_test.py | 38 |
3 files changed, 65 insertions, 4 deletions
diff --git a/sources/pyside6/libpyside/feature_select.cpp b/sources/pyside6/libpyside/feature_select.cpp index 567ae79e0..cf55ae7cf 100644 --- a/sources/pyside6/libpyside/feature_select.cpp +++ b/sources/pyside6/libpyside/feature_select.cpp @@ -614,6 +614,28 @@ PyObject *adjustPropertyName(PyObject *dict, PyObject *name) return name; } +static QByteArrayList GetPropertyStringsMro(PyTypeObject *type) +{ + /* + * PYSIDE-2042: There are possibly more methods which should become properties, + * because the wrapping process does not obey inheritance. + * Therefore, we need to walk the mro to find property strings. + */ + auto res = QByteArrayList(); + + PyObject *mro = type->tp_mro; + Py_ssize_t idx, n = PyTuple_GET_SIZE(mro); + // We leave 'Shiboken.Object' and 'object' alone, therefore "n - 2". + for (idx = 0; idx < n - 2; idx++) { + auto *subType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx)); + auto props = SbkObjectType_GetPropertyStrings(subType); + if (props != nullptr) + for (; *props != nullptr; ++props) + res << QByteArray(*props); + } + return res; +} + static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, int id) { /* @@ -643,12 +665,12 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in } // We then replace methods by properties. bool lower = (id & 0x01) != 0; - auto props = SbkObjectType_GetPropertyStrings(type); - if (props == nullptr || *props == nullptr) + auto props = GetPropertyStringsMro(type); + if (props.isEmpty()) return true; - for (; *props != nullptr; ++props) { + + for (const auto &propStr : std::as_const(props)) { bool isStdWrite; - auto propStr = *props; auto fields = parseFields(propStr, &isStdWrite); bool haveWrite = fields.size() == 3; PyObject *name = make_snake_case(fields[0], lower); diff --git a/sources/pyside6/tests/pysidetest/CMakeLists.txt b/sources/pyside6/tests/pysidetest/CMakeLists.txt index e88b866c4..d0932509e 100644 --- a/sources/pyside6/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside6/tests/pysidetest/CMakeLists.txt @@ -149,6 +149,7 @@ PYSIDE_TEST(new_inherited_functions_test.py) PYSIDE_TEST(notify_id.py) PYSIDE_TEST(properties_test.py) PYSIDE_TEST(property_python_test.py) +PYSIDE_TEST(true_property_test.py) PYSIDE_TEST(qapp_like_a_macro_test.py) PYSIDE_TEST(qvariant_test.py) PYSIDE_TEST(repr_test.py) diff --git a/sources/pyside6/tests/pysidetest/true_property_test.py b/sources/pyside6/tests/pysidetest/true_property_test.py new file mode 100644 index 000000000..671cc4571 --- /dev/null +++ b/sources/pyside6/tests/pysidetest/true_property_test.py @@ -0,0 +1,38 @@ +# Copyright (C) 2022 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) + +""" +PYSIDE-2042: Tests true_property with inheritance +""" + +from PySide6.QtCore import QSize +from PySide6.QtWidgets import QWidget, QSpinBox +from __feature__ import true_property +from helper.usesqapplication import UsesQApplication + + +class TruePropertyInheritanceTest(UsesQApplication): + + def testTrueProperty(self): + # this worked + widget = QWidget() + check = widget.sizeHint + self.assertEqual(type(check), QSize) + + # PYSIDE-2042: inheritance did not work + spin_box = QSpinBox() + check = spin_box.sizeHint + self.assertEqual(type(check), QSize) + + +if __name__ == '__main__': + unittest.main() |