aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2021-11-05 09:14:53 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2021-11-05 11:49:54 +0100
commit391e47893c463da5b91024508b739e51ecdaaf45 (patch)
tree755dc6b346bd175eeb504cbdd917ec3ef954b43e
parentd8cd97b050c68f352fef1df375c5c98f1daae029 (diff)
shiboken6: Handle PySets as function parameters
Python sets are iterable but not of sequence type. While the existing converter code from the templates uses iterators, the built-in check functions convertibleSequenceTypes()/checkSequenceTypes() assume a PySequence and would fail for PySets. Add new check functions convertibleIterableTypes()/checkIterableTypes() using iterators and use them for PySet. Add a test and a test for lists as a drive-by. [ChangeLog][PySide6] sets are now supported for functions taking a QSet. Pick-to: 6.2 Task-number: PYSIDE-174 Task-number: PYSIDE-1666 Change-Id: I883869162e7dfa9cd0e1669f941fb7864f0cf825 Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r--sources/pyside6/tests/pysidetest/container_test.py20
-rw-r--r--sources/pyside6/tests/pysidetest/containertest.cpp20
-rw-r--r--sources/pyside6/tests/pysidetest/containertest.h8
-rw-r--r--sources/shiboken6/generator/shiboken/shibokengenerator.cpp14
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.cpp50
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.h12
6 files changed, 117 insertions, 7 deletions
diff --git a/sources/pyside6/tests/pysidetest/container_test.py b/sources/pyside6/tests/pysidetest/container_test.py
index 14feb4465..1b5a94f31 100644
--- a/sources/pyside6/tests/pysidetest/container_test.py
+++ b/sources/pyside6/tests/pysidetest/container_test.py
@@ -45,6 +45,9 @@ EXPECTED_DICT = {1: ["v1"], 2: ["v2_1", "v2_2"],
4: ["v4_1", "v4_2"]}
+EXPECTED_LIST = [1, 2]
+
+
def sort_values(m):
"""Sort value lists in dicts since passing through a QMultiMap changes the order"""
result = {}
@@ -67,7 +70,22 @@ class ContainerTestTest(unittest.TestCase):
m2 = ContainerTest.passThroughMultiHash(m1)
self.assertEqual(sort_values(m2), EXPECTED_DICT)
+ def testList(self):
+ l1 = ContainerTest.createList();
+ self.assertEqual(l1, EXPECTED_LIST)
+ l2 = ContainerTest.passThroughList(l1)
+ self.assertEqual(l2, EXPECTED_LIST)
+
+ def testSet(self):
+ # FIXME PYSIDE 7: A PySet should be returned from QSet (currently PyList)
+ s1 = set(ContainerTest.createSet()); # Order is not predictable
+ s2 = set(ContainerTest.passThroughSet(s1))
+ self.assertEqual(sorted(list(s1)), sorted(list(s2)))
+
+ # Since lists are iterable, it should be possible to pass them to set API
+ l2 = ContainerTest.passThroughSet(EXPECTED_LIST)
+ self.assertEqual(sorted(l2), EXPECTED_LIST)
+
if __name__ == '__main__':
unittest.main()
-
diff --git a/sources/pyside6/tests/pysidetest/containertest.cpp b/sources/pyside6/tests/pysidetest/containertest.cpp
index ccb90b12f..9debfa5b7 100644
--- a/sources/pyside6/tests/pysidetest/containertest.cpp
+++ b/sources/pyside6/tests/pysidetest/containertest.cpp
@@ -60,3 +60,23 @@ QMultiHash<int, QString> ContainerTest::passThroughMultiHash(const QMultiHash<in
{
return in;
}
+
+QList<int> ContainerTest::createList()
+{
+ return {1, 2};
+}
+
+QList<int> ContainerTest::passThroughList(const QList<int> &list)
+{
+ return list;
+}
+
+QSet<int> ContainerTest::createSet()
+{
+ return {1, 2};
+}
+
+QSet<int> ContainerTest::passThroughSet(const QSet<int> &set)
+{
+ return set;
+}
diff --git a/sources/pyside6/tests/pysidetest/containertest.h b/sources/pyside6/tests/pysidetest/containertest.h
index 3405b6722..f214bdd40 100644
--- a/sources/pyside6/tests/pysidetest/containertest.h
+++ b/sources/pyside6/tests/pysidetest/containertest.h
@@ -31,9 +31,11 @@
#include "pysidetest_macros.h"
#include <QtCore/QObject>
+#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QMultiMap>
#include <QtCore/QMultiHash>
+#include <QtCore/QSet>
#include <QtCore/QString>
class PYSIDETEST_API ContainerTest
@@ -48,4 +50,10 @@ public:
static QMultiHash<int, QString> createMultiHash();
static QMultiHash<int, QString> passThroughMultiHash(const QMultiHash<int, QString> &in);
+
+ static QList<int> createList();
+ static QList<int> passThroughList(const QList<int> &list);
+
+ static QSet<int> createSet();
+ static QSet<int> passThroughSet(const QSet<int> &set);
};
diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
index 8dbf6b68a..788d6903c 100644
--- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp
@@ -928,16 +928,18 @@ QString ShibokenGenerator::cpythonCheckFunction(AbstractMetaType metaType) const
static_cast<const ContainerTypeEntry *>(typeEntry)->containerKind();
if (type == ContainerTypeEntry::ListContainer
|| type == ContainerTypeEntry::SetContainer) {
+ const QString containerType = type == ContainerTypeEntry::SetContainer
+ ? u"Iterable"_qs : u"Sequence"_qs;
const AbstractMetaType &type = metaType.instantiations().constFirst();
if (type.isPointerToWrapperType()) {
- typeCheck += u"checkSequenceTypes("_qs + cpythonTypeNameExt(type)
- + u", "_qs;
+ typeCheck += u"check"_qs + containerType + u"Types("_qs
+ + cpythonTypeNameExt(type) + u", "_qs;
} else if (type.isWrapperType()) {
- typeCheck += u"convertibleSequenceTypes("_qs +
- cpythonTypeNameExt(type) + u", "_qs;
+ typeCheck += u"convertible"_qs + containerType
+ + u"Types("_qs + cpythonTypeNameExt(type) + u", "_qs;
} else {
- typeCheck += u"convertibleSequenceTypes("_qs + converterObject(type)
- + u", "_qs;
+ typeCheck += u"convertible"_qs + containerType
+ + u"Types("_qs + converterObject(type) + u", "_qs;
}
} else if (type == ContainerTypeEntry::MapContainer
|| type == ContainerTypeEntry::MultiMapContainer
diff --git a/sources/shiboken6/libshiboken/sbkconverter.cpp b/sources/shiboken6/libshiboken/sbkconverter.cpp
index 334fb4297..e8c49660c 100644
--- a/sources/shiboken6/libshiboken/sbkconverter.cpp
+++ b/sources/shiboken6/libshiboken/sbkconverter.cpp
@@ -464,6 +464,27 @@ SbkConverter *primitiveTypeConverter(int index)
return PrimitiveTypeConverters[index];
}
+bool checkIterableTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ Shiboken::AutoDecRef it(PyObject_GetIter(pyIn));
+ if (it.isNull()) {
+ PyErr_Clear();
+ return false;
+ }
+
+ while (true) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ if (!PyObject_TypeCheck(pyItem, type))
+ return false;
+ }
+ return true;
+}
+
bool checkSequenceTypes(PyTypeObject *type, PyObject *pyIn)
{
assert(type);
@@ -480,6 +501,28 @@ bool checkSequenceTypes(PyTypeObject *type, PyObject *pyIn)
}
return true;
}
+
+bool convertibleIterableTypes(const SbkConverter *converter, PyObject *pyIn)
+{
+ Shiboken::AutoDecRef it(PyObject_GetIter(pyIn));
+ if (it.isNull()) {
+ PyErr_Clear();
+ return false;
+ }
+
+ while (true) {
+ Shiboken::AutoDecRef pyItem(PyIter_Next(it.object()));
+ if (pyItem.isNull()) {
+ if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration))
+ PyErr_Clear();
+ break;
+ }
+ if (!isPythonToCppConvertible(converter, pyItem))
+ return false;
+ }
+ return true;
+}
+
bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn)
{
assert(converter);
@@ -500,6 +543,13 @@ bool convertibleSequenceTypes(PyTypeObject *type, PyObject *pyIn)
return convertibleSequenceTypes(sotp->converter, pyIn);
}
+bool convertibleIterableTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(type);
+ auto *sotp = PepType_SOTP(type);
+ return convertibleIterableTypes(sotp->converter, pyIn);
+}
+
bool checkPairTypes(PyTypeObject *firstType, PyTypeObject *secondType, PyObject *pyIn)
{
assert(firstType);
diff --git a/sources/shiboken6/libshiboken/sbkconverter.h b/sources/shiboken6/libshiboken/sbkconverter.h
index 0cf8e5c0d..2f2dd8ef8 100644
--- a/sources/shiboken6/libshiboken/sbkconverter.h
+++ b/sources/shiboken6/libshiboken/sbkconverter.h
@@ -309,12 +309,24 @@ LIBSHIBOKEN_API SbkConverter *primitiveTypeConverter(int index);
/// Returns true if a Python sequence is comprised of objects of the given \p type.
LIBSHIBOKEN_API bool checkSequenceTypes(PyTypeObject *type, PyObject *pyIn);
+/// Returns true if a Python type is iterable and comprised of objects of the
+/// given \p type.
+LIBSHIBOKEN_API bool checkIterableTypes(PyTypeObject *type, PyObject *pyIn);
+
/// Returns true if a Python sequence is comprised of objects of a type convertible to the one represented by the given \p converter.
LIBSHIBOKEN_API bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn);
/// Returns true if a Python sequence is comprised of objects of a type convertible to \p type.
LIBSHIBOKEN_API bool convertibleSequenceTypes(PyTypeObject *type, PyObject *pyIn);
+/// Returns true if a Python type is iterable and comprised of objects of a
+/// type convertible to the one represented by the given \p converter.
+LIBSHIBOKEN_API bool convertibleIterableTypes(const SbkConverter *converter, PyObject *pyIn);
+
+/// Returns true if a Python type is iterable and comprised of objects of a
+/// type convertible to \p type.
+LIBSHIBOKEN_API bool convertibleIterableTypes(PyTypeObject *type, PyObject *pyIn);
+
/// Returns true if a Python sequence can be converted to a C++ pair.
LIBSHIBOKEN_API bool checkPairTypes(PyTypeObject *firstType, PyTypeObject *secondType, PyObject *pyIn);