diff options
| author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-11-05 09:14:53 +0100 |
|---|---|---|
| committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2021-11-05 11:49:54 +0100 |
| commit | 391e47893c463da5b91024508b739e51ecdaaf45 (patch) | |
| tree | 755dc6b346bd175eeb504cbdd917ec3ef954b43e | |
| parent | d8cd97b050c68f352fef1df375c5c98f1daae029 (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.py | 20 | ||||
| -rw-r--r-- | sources/pyside6/tests/pysidetest/containertest.cpp | 20 | ||||
| -rw-r--r-- | sources/pyside6/tests/pysidetest/containertest.h | 8 | ||||
| -rw-r--r-- | sources/shiboken6/generator/shiboken/shibokengenerator.cpp | 14 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/sbkconverter.cpp | 50 | ||||
| -rw-r--r-- | sources/shiboken6/libshiboken/sbkconverter.h | 12 |
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); |
