aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/libshiboken/sbkconverter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/libshiboken/sbkconverter.cpp')
-rw-r--r--sources/shiboken6/libshiboken/sbkconverter.cpp454
1 files changed, 382 insertions, 72 deletions
diff --git a/sources/shiboken6/libshiboken/sbkconverter.cpp b/sources/shiboken6/libshiboken/sbkconverter.cpp
index 0aabe5f60..9ab674415 100644
--- a/sources/shiboken6/libshiboken/sbkconverter.cpp
+++ b/sources/shiboken6/libshiboken/sbkconverter.cpp
@@ -1,45 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "sbkconverter.h"
#include "sbkconverter_p.h"
#include "sbkarrayconverter_p.h"
+#include "sbkmodule.h"
#include "basewrapper_p.h"
#include "bindingmanager.h"
#include "autodecref.h"
@@ -47,15 +12,19 @@
#include "voidptr.h"
#include <string>
+#include <cstring>
+#include <iostream>
#include <unordered_map>
+#include <unordered_set>
+#include <map>
+#include <set>
static SbkConverter **PrimitiveTypeConverters;
using ConvertersMap = std::unordered_map<std::string, SbkConverter *>;
static ConvertersMap converters;
-namespace Shiboken {
-namespace Conversions {
+namespace Shiboken::Conversions {
void initArrayConverters();
@@ -73,6 +42,7 @@ void init()
Primitive<short>::createConverter(),
Primitive<signed char>::createConverter(),
Primitive<std::string>::createConverter(),
+ Primitive<std::wstring>::createConverter(),
Primitive<unsigned PY_LONG_LONG>::createConverter(),
Primitive<unsigned char>::createConverter(),
Primitive<unsigned int>::createConverter(),
@@ -95,6 +65,7 @@ void init()
converters["short"] = primitiveTypeConverters[SBK_SHORT_IDX];
converters["signed char"] = primitiveTypeConverters[SBK_SIGNEDCHAR_IDX];
converters["std::string"] = primitiveTypeConverters[SBK_STD_STRING_IDX];
+ converters["std::wstring"] = primitiveTypeConverters[SBK_STD_WSTRING_IDX];
converters["unsigned PY_LONG_LONG"] = primitiveTypeConverters[SBK_UNSIGNEDPY_LONG_LONG_IDX];
converters["unsigned char"] = primitiveTypeConverters[SBK_UNSIGNEDCHAR_IDX];
converters["unsigned int"] = primitiveTypeConverters[SBK_UNSIGNEDINT_IDX];
@@ -106,6 +77,103 @@ void init()
initArrayConverters();
}
+static void dumpPyTypeObject(std::ostream &str, PyTypeObject *t)
+{
+ str << "\nPython type ";
+ if (t == nullptr) {
+ str << "<None>";
+ return;
+ }
+ str << '"' << t->tp_name << '"';
+ if (t->tp_base != nullptr && t->tp_base != &PyBaseObject_Type)
+ str << '(' << t->tp_base->tp_name << ')';
+}
+
+static void dumpSbkConverter(std::ostream &str, const SbkConverter *c)
+{
+ str << "SbkConverter " << static_cast<const void *>(c) << ": ";
+ if (c->pointerToPython != nullptr)
+ str << ", C++ pointer->Python";
+ if (c->copyToPython != nullptr)
+ str << ", copy->Python";
+ if (c->toCppPointerConversion.second != nullptr)
+ str << ", Python->C++ pointer";
+ if (!c->toCppConversions.empty())
+ str << ", " << c->toCppConversions.size() << " Python->C++ conversions";
+}
+
+// Less than operator for a PyTypeObject for dumping the converter map
+static bool pyTypeObjectLessThan(const PyTypeObject *t1, const PyTypeObject *t2)
+{
+ const bool isNull1 = t1 == nullptr;
+ const bool isNull2 = t2 == nullptr;
+ if (isNull1 || isNull2)
+ return isNull1 && !isNull2;
+ // Internal types (lower case) first
+ const bool isInternal1 = std::islower(t1->tp_name[0]);
+ const bool isInternal2 = std::islower(t2->tp_name[0]);
+ if (isInternal1 != isInternal2)
+ return !isInternal2;
+ return std::strcmp(t1->tp_name, t2->tp_name) < 0;
+}
+
+void dumpConverters()
+{
+ struct PyTypeObjectLess {
+
+ bool operator()(const PyTypeObject *t1, const PyTypeObject *t2) const {
+ return pyTypeObjectLessThan(t1, t2);
+ }
+ };
+
+ using StringSet = std::set<std::string>;
+ using SbkConverterNamesMap = std::unordered_map<SbkConverter *, StringSet>;
+ using PyTypeObjectConverterMap = std::map<PyTypeObject *, SbkConverterNamesMap,
+ PyTypeObjectLess>;
+
+ auto &str = std::cerr;
+
+ // Sort the entries by the associated PyTypeObjects and converters
+ PyTypeObjectConverterMap pyTypeObjectConverterMap;
+ for (const auto &converter : converters) {
+ auto *sbkConverter = converter.second;
+ if (sbkConverter == nullptr) {
+ str << "Non-existent: \"" << converter.first << "\"\n";
+ continue;
+ }
+ auto *typeObject = sbkConverter->pythonType;
+ auto typeIt = pyTypeObjectConverterMap.find(typeObject);
+ if (typeIt == pyTypeObjectConverterMap.end())
+ typeIt = pyTypeObjectConverterMap.insert(std::make_pair(typeObject,
+ SbkConverterNamesMap{})).first;
+ SbkConverterNamesMap &sbkConverterMap = typeIt->second;
+ auto convIt = sbkConverterMap.find(sbkConverter);
+ if (convIt == sbkConverterMap.end())
+ convIt = sbkConverterMap.insert(std::make_pair(sbkConverter,
+ StringSet{})).first;
+ convIt->second.insert(converter.first);
+ }
+
+ for (const auto &tc : pyTypeObjectConverterMap) {
+ dumpPyTypeObject(str, tc.first);
+ str << ", " << tc.second.size() << " converter(s):\n";
+ for (const auto &cn : tc.second) {
+ str << " ";
+ dumpSbkConverter(str, cn.first);
+ str << ", " << cn.second.size() << " alias(es):";
+ int i = 0;
+ for (const auto &name : cn.second) {
+ if ((i++ % 5) == 0)
+ str << "\n ";
+ str << " \"" << name << '"';
+ }
+ str << '\n';
+ }
+ }
+
+ str << '\n';
+}
+
SbkConverter *createConverterObject(PyTypeObject *type,
PythonToCppFunc toCppPointerConvFunc,
IsConvertibleToCppFunc toCppPointerCheckFunc,
@@ -127,14 +195,14 @@ SbkConverter *createConverterObject(PyTypeObject *type,
return converter;
}
-SbkConverter *createConverter(SbkObjectType *type,
+SbkConverter *createConverter(PyTypeObject *type,
PythonToCppFunc toCppPointerConvFunc,
IsConvertibleToCppFunc toCppPointerCheckFunc,
CppToPythonFunc pointerToPythonFunc,
CppToPythonFunc copyToPythonFunc)
{
SbkConverter *converter =
- createConverterObject(reinterpret_cast<PyTypeObject *>(type),
+ createConverterObject(type,
toCppPointerConvFunc, toCppPointerCheckFunc,
pointerToPythonFunc, copyToPythonFunc);
PepType_SOTP(type)->converter = converter;
@@ -172,16 +240,26 @@ void addPythonToCppValueConversion(SbkConverter *converter,
{
converter->toCppConversions.push_back(std::make_pair(isConvertibleToCppFunc, pythonToCppFunc));
}
-void addPythonToCppValueConversion(SbkObjectType *type,
+
+void addPythonToCppValueConversion(PyTypeObject *type,
+ PythonToCppFunc pythonToCppFunc,
+ IsConvertibleToCppFunc isConvertibleToCppFunc)
+{
+ auto *sotp = PepType_SOTP(type);
+ addPythonToCppValueConversion(sotp->converter, pythonToCppFunc, isConvertibleToCppFunc);
+}
+
+void addPythonToCppValueConversion(Shiboken::Module::TypeInitStruct typeStruct,
PythonToCppFunc pythonToCppFunc,
IsConvertibleToCppFunc isConvertibleToCppFunc)
{
- addPythonToCppValueConversion(PepType_SOTP(type)->converter, pythonToCppFunc, isConvertibleToCppFunc);
+ addPythonToCppValueConversion(typeStruct.type, pythonToCppFunc, isConvertibleToCppFunc);
}
-PyObject *pointerToPython(SbkObjectType *type, const void *cppIn)
+PyObject *pointerToPython(PyTypeObject *type, const void *cppIn)
{
- return pointerToPython(PepType_SOTP(type)->converter, cppIn);
+ auto *sotp = PepType_SOTP(type);
+ return pointerToPython(sotp->converter, cppIn);
}
PyObject *pointerToPython(const SbkConverter *converter, const void *cppIn)
@@ -197,9 +275,10 @@ PyObject *pointerToPython(const SbkConverter *converter, const void *cppIn)
return converter->pointerToPython(cppIn);
}
-PyObject *referenceToPython(SbkObjectType *type, const void *cppIn)
+PyObject *referenceToPython(PyTypeObject *type, const void *cppIn)
{
- return referenceToPython(PepType_SOTP(type)->converter, cppIn);
+ auto *sotp = PepType_SOTP(type);
+ return referenceToPython(sotp->converter, cppIn);
}
PyObject *referenceToPython(const SbkConverter *converter, const void *cppIn)
@@ -230,19 +309,37 @@ static inline PyObject *CopyCppToPython(const SbkConverter *converter, const voi
}
return converter->copyToPython(cppIn);
}
-PyObject *copyToPython(SbkObjectType *type, const void *cppIn)
+
+PyObject *copyToPython(PyTypeObject *type, const void *cppIn)
{
- return CopyCppToPython(PepType_SOTP(type)->converter, cppIn);
+ auto *sotp = PepType_SOTP(type);
+ return CopyCppToPython(sotp->converter, cppIn);
}
+
PyObject *copyToPython(const SbkConverter *converter, const void *cppIn)
{
return CopyCppToPython(converter, cppIn);
}
-PythonToCppFunc isPythonToCppPointerConvertible(SbkObjectType *type, PyObject *pyIn)
+PythonToCppFunc isPythonToCppPointerConvertible(PyTypeObject *type, PyObject *pyIn)
{
assert(pyIn);
- return PepType_SOTP(type)->converter->toCppPointerConversion.first(pyIn);
+ auto *sotp = PepType_SOTP(type);
+ return sotp->converter->toCppPointerConversion.first(pyIn);
+}
+
+PythonToCppConversion pythonToCppPointerConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (PythonToCppFunc toCppPtr = isPythonToCppPointerConvertible(type, pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ return {};
+}
+
+PythonToCppConversion pythonToCppPointerConversion(Module::TypeInitStruct typeStruct, PyObject *pyIn)
+{
+ return pythonToCppPointerConversion(typeStruct.type, pyIn);
}
static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
@@ -254,15 +351,47 @@ static inline PythonToCppFunc IsPythonToCppConvertible(const SbkConverter *conve
}
return nullptr;
}
-PythonToCppFunc isPythonToCppValueConvertible(SbkObjectType *type, PyObject *pyIn)
+
+PythonToCppFunc isPythonToCppValueConvertible(PyTypeObject *type, PyObject *pyIn)
{
- return IsPythonToCppConvertible(PepType_SOTP(type)->converter, pyIn);
+ auto *sotp = PepType_SOTP(type);
+ return IsPythonToCppConvertible(sotp->converter, pyIn);
}
+
+PythonToCppConversion pythonToCppValueConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (PythonToCppFunc toCppVal = isPythonToCppValueConvertible(type, pyIn))
+ return {toCppVal, PythonToCppConversion::Value};
+ return {};
+}
+
PythonToCppFunc isPythonToCppConvertible(const SbkConverter *converter, PyObject *pyIn)
{
return IsPythonToCppConvertible(converter, pyIn);
}
+PythonToCppConversion pythonToCppReferenceConversion(const SbkConverter *converter, PyObject *pyIn)
+{
+ if (converter->toCppPointerConversion.first) {
+ if (auto toCppPtr = converter->toCppPointerConversion.first(pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ }
+ for (const ToCppConversion &c : converter->toCppConversions) {
+ if (PythonToCppFunc toCppFunc = c.first(pyIn))
+ return {toCppFunc, PythonToCppConversion::Value};
+ }
+ return {};
+}
+
+PythonToCppConversion pythonToCppConversion(const SbkConverter *converter, PyObject *pyIn)
+{
+ if (auto func = IsPythonToCppConvertible(converter, pyIn))
+ return {func, PythonToCppConversion::Value};
+ return {};
+}
+
PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter,
int dim1, int dim2, PyObject *pyIn)
{
@@ -274,7 +403,15 @@ PythonToCppFunc isPythonToCppConvertible(const SbkArrayConverter *converter,
return nullptr;
}
-PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType *type, PyObject *pyIn)
+LIBSHIBOKEN_API PythonToCppConversion pythonToCppConversion(const SbkArrayConverter *converter,
+ int dim1, int dim2, PyObject *pyIn)
+{
+ if (auto func = isPythonToCppConvertible(converter, dim1, dim2, pyIn))
+ return {func, PythonToCppConversion::Value};
+ return {};
+}
+
+PythonToCppFunc isPythonToCppReferenceConvertible(PyTypeObject *type, PyObject *pyIn)
{
if (pyIn != Py_None) {
PythonToCppFunc toCpp = isPythonToCppPointerConvertible(type, pyIn);
@@ -284,6 +421,19 @@ PythonToCppFunc isPythonToCppReferenceConvertible(SbkObjectType *type, PyObject
return isPythonToCppValueConvertible(type, pyIn);
}
+PythonToCppConversion pythonToCppReferenceConversion(PyTypeObject *type, PyObject *pyIn)
+{
+ if (pyIn == nullptr)
+ return {};
+ if (pyIn != Py_None) {
+ if (PythonToCppFunc toCppPtr = isPythonToCppPointerConvertible(type, pyIn))
+ return {toCppPtr, PythonToCppConversion::Pointer};
+ }
+ if (PythonToCppFunc toCppVal = isPythonToCppValueConvertible(type, pyIn))
+ return {toCppVal, PythonToCppConversion::Value};
+ return {};
+}
+
void nonePythonToCppNullPtr(PyObject *, void *cppOut)
{
assert(cppOut);
@@ -295,20 +445,20 @@ void *cppPointer(PyTypeObject *desiredType, SbkObject *pyIn)
assert(pyIn);
if (!ObjectType::checkType(desiredType))
return pyIn;
- auto *inType = reinterpret_cast<SbkObjectType *>(Py_TYPE(pyIn));
+ auto *inType = Py_TYPE(pyIn);
if (ObjectType::hasCast(inType))
return ObjectType::cast(inType, pyIn, desiredType);
return Object::cppPointer(pyIn, desiredType);
}
-void pythonToCppPointer(SbkObjectType *type, PyObject *pyIn, void *cppOut)
+void pythonToCppPointer(PyTypeObject *type, PyObject *pyIn, void *cppOut)
{
assert(type);
assert(pyIn);
assert(cppOut);
*reinterpret_cast<void **>(cppOut) = pyIn == Py_None
? nullptr
- : cppPointer(reinterpret_cast<PyTypeObject *>(type), reinterpret_cast<SbkObject *>(pyIn));
+ : cppPointer(type, reinterpret_cast<SbkObject *>(pyIn));
}
void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
@@ -318,7 +468,7 @@ void pythonToCppPointer(const SbkConverter *converter, PyObject *pyIn, void *cpp
assert(cppOut);
*reinterpret_cast<void **>(cppOut) = pyIn == Py_None
? nullptr
- : cppPointer(reinterpret_cast<PyTypeObject *>(converter->pythonType), reinterpret_cast<SbkObject *>(pyIn));
+ : cppPointer(converter->pythonType, reinterpret_cast<SbkObject *>(pyIn));
}
static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
@@ -331,10 +481,11 @@ static void _pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void
toCpp(pyIn, cppOut);
}
-void pythonToCppCopy(SbkObjectType *type, PyObject *pyIn, void *cppOut)
+void pythonToCppCopy(PyTypeObject *type, PyObject *pyIn, void *cppOut)
{
assert(type);
- _pythonToCppCopy(PepType_SOTP(type)->converter, pyIn, cppOut);
+ auto *sotp = PepType_SOTP(type);
+ _pythonToCppCopy(sotp->converter, pyIn, cppOut);
}
void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut)
@@ -342,16 +493,17 @@ void pythonToCppCopy(const SbkConverter *converter, PyObject *pyIn, void *cppOut
_pythonToCppCopy(converter, pyIn, cppOut);
}
-bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCppFunc)
+bool isImplicitConversion(PyTypeObject *type, PythonToCppFunc toCppFunc)
{
+ auto *sotp = PepType_SOTP(type);
// This is the Object Type or Value Type conversion that only
// retrieves the C++ pointer held in the Python wrapper.
- if (toCppFunc == PepType_SOTP(type)->converter->toCppPointerConversion.second)
+ if (toCppFunc == sotp->converter->toCppPointerConversion.second)
return false;
// Object Types doesn't have any kind of value conversion,
// only C++ pointer retrieval.
- if (PepType_SOTP(type)->converter->toCppConversions.empty())
+ if (sotp->converter->toCppConversions.empty())
return false;
// The first conversion of the non-pointer conversion list is
@@ -361,23 +513,59 @@ bool isImplicitConversion(SbkObjectType *type, PythonToCppFunc toCppFunc)
// Note that we don't check if the Python to C++ conversion is in
// the list of the type's conversions, for it is expected that the
// caller knows what he's doing.
- const auto conv = PepType_SOTP(type)->converter->toCppConversions.cbegin();
+ const auto conv = sotp->converter->toCppConversions.cbegin();
return toCppFunc != (*conv).second;
}
-void registerConverterName(SbkConverter *converter , const char *typeName)
+void registerConverterName(SbkConverter *converter, const char *typeName)
{
auto iter = converters.find(typeName);
if (iter == converters.end())
converters.insert(std::make_pair(typeName, converter));
}
-SbkConverter *getConverter(const char *typeName)
+static std::string getRealTypeName(const std::string &typeName)
+{
+ auto size = typeName.size();
+ if (std::isalnum(typeName[size - 1]) == 0)
+ return typeName.substr(0, size - 1);
+ return typeName;
+}
+
+// PYSIDE-2404: Build a negative cache of already failed lookups.
+// The resulting list must be reset after each new import,
+// because that can change results. Also clear the cache after
+// reaching some threashold.
+static std::unordered_set<std::string> nonExistingTypeNames{};
+
+// Arbitrary size limit to prevent random name overflows.
+static constexpr std::size_t negativeCacheLimit = 50;
+
+static void rememberAsNonexistent(const std::string &typeName)
{
- ConvertersMap::const_iterator it = converters.find(typeName);
+ if (nonExistingTypeNames.size() > negativeCacheLimit)
+ clearNegativeLazyCache();
+ converters.insert(std::make_pair(typeName, nullptr));
+ nonExistingTypeNames.insert(typeName);
+}
+
+SbkConverter *getConverter(const char *typeNameC)
+{
+ std::string typeName = typeNameC;
+ auto it = converters.find(typeName);
+ // PYSIDE-2404: This can also contain explicit nullptr as a negative cache.
+ if (it != converters.end())
+ return it->second;
+ // PYSIDE-2404: Did not find the name. Load the lazy classes
+ // which have this name and try again.
+ Shiboken::Module::loadLazyClassesWithName(getRealTypeName(typeName).c_str());
+ it = converters.find(typeName);
if (it != converters.end())
return it->second;
- if (Py_VerboseFlag > 0) {
+ // Cache the negative result. Don't forget to clear the cache for new modules.
+ rememberAsNonexistent(typeName);
+
+ if (Shiboken::pyVerbose() > 0) {
const std::string message =
std::string("Can't find type resolver for type '") + typeName + "'.";
PyErr_WarnEx(PyExc_RuntimeWarning, message.c_str(), 0);
@@ -385,11 +573,41 @@ SbkConverter *getConverter(const char *typeName)
return nullptr;
}
+void clearNegativeLazyCache()
+{
+ for (const auto &typeName : nonExistingTypeNames) {
+ auto it = converters.find(typeName);
+ converters.erase(it);
+ }
+ nonExistingTypeNames.clear();
+}
+
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);
@@ -406,6 +624,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);
@@ -419,10 +659,18 @@ bool convertibleSequenceTypes(const SbkConverter *converter, PyObject *pyIn)
}
return true;
}
-bool convertibleSequenceTypes(SbkObjectType *type, PyObject *pyIn)
+bool convertibleSequenceTypes(PyTypeObject *type, PyObject *pyIn)
+{
+ assert(type);
+ auto *sotp = PepType_SOTP(type);
+ return convertibleSequenceTypes(sotp->converter, pyIn);
+}
+
+bool convertibleIterableTypes(PyTypeObject *type, PyObject *pyIn)
{
assert(type);
- return convertibleSequenceTypes(PepType_SOTP(type)->converter, pyIn);
+ auto *sotp = PepType_SOTP(type);
+ return convertibleIterableTypes(sotp->converter, pyIn);
}
bool checkPairTypes(PyTypeObject *firstType, PyTypeObject *secondType, PyObject *pyIn)
@@ -489,6 +737,33 @@ bool checkDictTypes(PyTypeObject *keyType, PyTypeObject *valueType, PyObject *py
return true;
}
+bool checkMultiDictTypes(PyTypeObject *keyType, PyTypeObject *valueType,
+ PyObject *pyIn)
+{
+ assert(keyType);
+ assert(valueType);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+
+ PyObject *key;
+ PyObject *values;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &values)) {
+ if (!PyObject_TypeCheck(key, keyType))
+ return false;
+ if (!PySequence_Check(values))
+ return false;
+ const Py_ssize_t size = PySequence_Size(values);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ AutoDecRef value(PySequence_GetItem(values, i));
+ if (!PyObject_TypeCheck(value, valueType))
+ return false;
+ }
+ }
+ return true;
+}
+
bool convertibleDictTypes(const SbkConverter *keyConverter, bool keyCheckExact, const SbkConverter *valueConverter,
bool valueCheckExact, PyObject *pyIn)
{
@@ -517,6 +792,41 @@ bool convertibleDictTypes(const SbkConverter *keyConverter, bool keyCheckExact,
return true;
}
+bool convertibleMultiDictTypes(const SbkConverter *keyConverter, bool keyCheckExact,
+ const SbkConverter *valueConverter,
+ bool valueCheckExact, PyObject *pyIn)
+{
+ assert(keyConverter);
+ assert(valueConverter);
+ assert(pyIn);
+ if (!PyDict_Check(pyIn))
+ return false;
+ PyObject *key;
+ PyObject *values;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(pyIn, &pos, &key, &values)) {
+ if (keyCheckExact) {
+ if (!PyObject_TypeCheck(key, keyConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(keyConverter, key)) {
+ return false;
+ }
+ if (!PySequence_Check(values))
+ return false;
+ const Py_ssize_t size = PySequence_Size(values);
+ for (Py_ssize_t i = 0; i < size; ++i) {
+ AutoDecRef value(PySequence_GetItem(values, i));
+ if (valueCheckExact) {
+ if (!PyObject_TypeCheck(value.object(), valueConverter->pythonType))
+ return false;
+ } else if (!isPythonToCppConvertible(valueConverter, value.object())) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
PyTypeObject *getPythonTypeObject(const SbkConverter *converter)
{
if (converter)
@@ -597,4 +907,4 @@ void SpecificConverter::toCpp(PyObject *pyIn, void *cppOut)
}
}
-} } // namespace Shiboken::Conversions
+} // namespace Shiboken::Conversions