diff options
-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() |