aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2022-11-16 14:58:28 +0100
committerChristian Tismer <tismer@stackless.com>2022-11-24 13:20:36 +0100
commita4329741e960bc9f9efc690ba849c55b32496191 (patch)
tree008be57f877637de1e14ab38d067666b3542fa6e
parentc4995ad3e0b3c089e033391e73e3b944de49263a (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.cpp30
-rw-r--r--sources/pyside6/tests/pysidetest/CMakeLists.txt1
-rw-r--r--sources/pyside6/tests/pysidetest/true_property_test.py38
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()