diff options
24 files changed, 204 insertions, 91 deletions
diff --git a/requirements-coin.txt b/requirements-coin.txt index 5ee2bac0d..a5dabc834 100644 --- a/requirements-coin.txt +++ b/requirements-coin.txt @@ -1,5 +1,5 @@ -pip>=24.2 -setuptools==72.1.0 +pip>=25 +setuptools==78.1.0 importlib_metadata>=6 importlib_resources>=5.10.2 packaging>=24 diff --git a/requirements.txt b/requirements.txt index ad4c91813..feb5a01aa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # Build dependencies -setuptools==72.1.0 -packaging==24.1 -build==1.2.1 +setuptools==78.1.0 +packaging==24.2 +build==1.2.2.post1 wheel==0.43.0 distro==1.9.0; sys_platform == 'linux' patchelf==0.17.2; sys_platform == 'linux' diff --git a/sources/pyside-tools/pyside_tool.py b/sources/pyside-tools/pyside_tool.py index 887f2bdda..5c009859d 100644 --- a/sources/pyside-tools/pyside_tool.py +++ b/sources/pyside-tools/pyside_tool.py @@ -198,6 +198,18 @@ def metaobjectdump(): pyside_script_wrapper("metaobjectdump.py") +def _check_requirements(requirements_file): + """Check if all required packages are installed.""" + missing_packages = [] + with open(requirements_file, 'r', encoding='UTF-8') as file: + for line in file: + # versions + package = line.strip().split('==')[0] + if not importlib.util.find_spec(package): + missing_packages.append(line.strip()) + return missing_packages + + def project(): pyside_script_wrapper("project.py") @@ -220,12 +232,15 @@ def android_deploy(): file=sys.stderr) else: android_requirements_file = Path(__file__).parent / "requirements-android.txt" - with open(android_requirements_file, 'r', encoding='UTF-8') as file: - while line := file.readline(): - dependent_package = line.rstrip() - if not bool(importlib.util.find_spec(dependent_package)): - command = [sys.executable, "-m", "pip", "install", dependent_package] - subprocess.run(command) + if android_requirements_file.exists(): + missing_packages = _check_requirements(android_requirements_file) + if missing_packages: + print("The following packages are required but not installed:") + for package in missing_packages: + print(f" - {package}") + print("Please install them using:") + print(f" pip install -r {android_requirements_file}") + sys.exit(1) pyside_script_wrapper("android_deploy.py") diff --git a/sources/pyside-tools/requirements-android.txt b/sources/pyside-tools/requirements-android.txt index 9ed5d8427..1a247f6c1 100644 --- a/sources/pyside-tools/requirements-android.txt +++ b/sources/pyside-tools/requirements-android.txt @@ -1,3 +1,4 @@ jinja2 pkginfo tqdm +packaging==24.1 diff --git a/sources/pyside6/libpyside/pysidevariantutils.cpp b/sources/pyside6/libpyside/pysidevariantutils.cpp index 7dbfb3afc..729557919 100644 --- a/sources/pyside6/libpyside/pysidevariantutils.cpp +++ b/sources/pyside6/libpyside/pysidevariantutils.cpp @@ -125,8 +125,12 @@ QMetaType resolveMetaType(PyTypeObject *type) // PYSIDE-1887, PYSIDE-86: Skip QObject base class of QGraphicsObject; // it needs to use always QGraphicsItem as a QVariant type for // QGraphicsItem::itemChange() to work. - if (qstrcmp(typeName, "QGraphicsObject*") == 0) - ++i; + if (qstrcmp(typeName, "QGraphicsObject*") == 0 && size > 1) { + auto *firstBaseType = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(type->tp_bases, 0)); + const char *firstBaseTypeName = Shiboken::ObjectType::getOriginalName(firstBaseType); + if (firstBaseTypeName != nullptr && qstrcmp(firstBaseTypeName, "QObject*") == 0) + ++i; + } for ( ; i < size; ++i) { auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GetItem(type->tp_bases, i)); const QMetaType derived = resolveMetaType(baseType); diff --git a/sources/pyside6/tests/QtWidgets/qgraphicsobjectreimpl_test.py b/sources/pyside6/tests/QtWidgets/qgraphicsobjectreimpl_test.py index 91b405aaf..7ae29d1f7 100644 --- a/sources/pyside6/tests/QtWidgets/qgraphicsobjectreimpl_test.py +++ b/sources/pyside6/tests/QtWidgets/qgraphicsobjectreimpl_test.py @@ -53,8 +53,16 @@ class QGraphicsObjectReimpl(UsesQApplication): # See also PYSIDE-1887, PYSIDE-3069 gobjA = GObjA() gobjA.setParentItem(w) + print(gobjA.parentItem()) self.assertIs(type(w), type(gobjA.parentItem())) + # PYSIDE-3115: QVariant conversion of the parent + # (Python class inheriting QGraphicsObject). + parentA = GObjA() + gobjA = GObjA() + gobjA.setParentItem(parentA) + self.assertIs(type(parentA), type(gobjA.parentItem())) + gobjB = GObjB() gobjB.setParentItem(w) self.assertIs(type(w), type(gobjB.parentItem())) diff --git a/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py b/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py index 120c54af3..14330726a 100644 --- a/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py +++ b/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py @@ -36,7 +36,7 @@ class DeployTestBase(unittest.TestCase): android_requirements_file = pyside_tools / "requirements-android.txt" with open(android_requirements_file, 'r', encoding='UTF-8') as file: while line := file.readline(): - dependent_package = line.rstrip() + dependent_package = line.rstrip().split('==')[0] if not bool(importlib.util.find_spec(dependent_package)): command = [sys.executable, "-m", "pip", "install", dependent_package] subprocess.run(command) diff --git a/sources/shiboken6/ApiExtractor/customconversion.cpp b/sources/shiboken6/ApiExtractor/customconversion.cpp index 4cfd1b974..b022cd692 100644 --- a/sources/shiboken6/ApiExtractor/customconversion.cpp +++ b/sources/shiboken6/ApiExtractor/customconversion.cpp @@ -5,6 +5,7 @@ #include "containertypeentry.h" #include "customtypenentry.h" #include "primitivetypeentry.h" +#include "smartpointertypeentry.h" #include "valuetypeentry.h" #include <QtCore/qdebug.h> @@ -95,6 +96,11 @@ QString TargetToNativeConversion::sourceTypeName() const QString TargetToNativeConversion::sourceTypeCheck() const { + return m_sourceTypeCheck; +} + +QString TargetToNativeConversion::sourceTypeCheckFallback() const +{ if (!m_sourceTypeCheck.isEmpty()) return m_sourceTypeCheck; @@ -108,6 +114,10 @@ QString TargetToNativeConversion::sourceTypeCheck() const } } + if (m_sourceTypeName == "Py_None"_L1 || m_sourceTypeName == "PyNone"_L1) + return "%in == Py_None"_L1; + if (m_sourceTypeName == "SbkObject"_L1) + return "Shiboken::Object::checkType(%in)"_L1; return {}; } @@ -139,6 +149,8 @@ CustomConversionPtr CustomConversion::getCustomConversion(const TypeEntryCPtr &t return std::static_pointer_cast<const ContainerTypeEntry>(type)->customConversion(); if (type->isValue()) return std::static_pointer_cast<const ValueTypeEntry>(type)->customConversion(); + if (type->isSmartPointer()) + return std::static_pointer_cast<const SmartPointerTypeEntry>(type)->customConversion(); return {}; } diff --git a/sources/shiboken6/ApiExtractor/customconversion.h b/sources/shiboken6/ApiExtractor/customconversion.h index a75178846..9125d6705 100644 --- a/sources/shiboken6/ApiExtractor/customconversion.h +++ b/sources/shiboken6/ApiExtractor/customconversion.h @@ -25,7 +25,10 @@ public: void setSourceType(const TypeEntryCPtr &sourceType); bool isCustomType() const; QString sourceTypeName() const; + // Check as specified in the type system QString sourceTypeCheck() const; + // Check with fallback bases on sourceType + QString sourceTypeCheckFallback() const; QString conversion() const; void setConversion(const QString &conversion); diff --git a/sources/shiboken6/ApiExtractor/smartpointertypeentry.h b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h index d704210f7..7b67647b9 100644 --- a/sources/shiboken6/ApiExtractor/smartpointertypeentry.h +++ b/sources/shiboken6/ApiExtractor/smartpointertypeentry.h @@ -5,6 +5,7 @@ #define SMARTPOINTERTYPEENTRY_H #include "complextypeentry.h" +#include "customconversion_typedefs.h" class SmartPointerTypeEntryPrivate; @@ -51,6 +52,10 @@ public: QString getTargetName(const AbstractMetaType &metaType) const; + bool hasCustomConversion() const; + void setCustomConversion(const CustomConversionPtr &customConversion); + CustomConversionPtr customConversion() const; + #ifndef QT_NO_DEBUG_STREAM void formatDebug(QDebug &d) const override; #endif diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index 0820150f8..46e88291d 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -2154,6 +2154,7 @@ public: QString m_resetMethod; SmartPointerTypeEntry::Instantiations m_instantiations; TypeEntryCList m_excludedInstantiations; + CustomConversionPtr m_customConversion; TypeSystem::SmartPointerType m_smartPointerType; }; @@ -2306,6 +2307,24 @@ QString SmartPointerTypeEntry::getTargetName(const AbstractMetaType &metaType) c return fixSmartPointerName(name); } +bool SmartPointerTypeEntry::hasCustomConversion() const +{ + S_D(const SmartPointerTypeEntry); + return bool(d->m_customConversion); +} + +void SmartPointerTypeEntry::setCustomConversion(const CustomConversionPtr &customConversion) +{ + S_D(SmartPointerTypeEntry); + d->m_customConversion = customConversion; +} + +CustomConversionPtr SmartPointerTypeEntry::customConversion() const +{ + S_D(const SmartPointerTypeEntry); + return d->m_customConversion; +} + // ----------------- NamespaceTypeEntry class NamespaceTypeEntryPrivate : public ComplexTypeEntryPrivate { diff --git a/sources/shiboken6/ApiExtractor/typesystemparser.cpp b/sources/shiboken6/ApiExtractor/typesystemparser.cpp index 8b2ad08de..7ae25e48c 100644 --- a/sources/shiboken6/ApiExtractor/typesystemparser.cpp +++ b/sources/shiboken6/ApiExtractor/typesystemparser.cpp @@ -2348,9 +2348,10 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, if (topElement != StackElement::ModifyArgument && topElement != StackElement::ValueTypeEntry && topElement != StackElement::PrimitiveTypeEntry - && topElement != StackElement::ContainerTypeEntry) { + && topElement != StackElement::ContainerTypeEntry + && topElement != StackElement::SmartPointerTypeEntry) { m_error = u"Conversion rules can only be specified for argument modification, " - "value-type, primitive-type or container-type conversion."_s; + "value-type, primitive-type, or container-type or smartpointer-type conversion."_s; return false; } @@ -2415,6 +2416,9 @@ bool TypeSystemParser::parseCustomConversion(const ConditionalStreamReader &, std::static_pointer_cast<ContainerTypeEntry>(top->entry)->setCustomConversion(customConversion); else if (top->entry->isValue()) std::static_pointer_cast<ValueTypeEntry>(top->entry)->setCustomConversion(customConversion); + else if (top->entry->isSmartPointer()) + std::static_pointer_cast<SmartPointerTypeEntry>(top->entry)->setCustomConversion(customConversion); + customConversionsForReview.append(customConversion); return true; } diff --git a/sources/shiboken6/cmake/ShibokenHelpers.cmake b/sources/shiboken6/cmake/ShibokenHelpers.cmake index bcaf31e89..c6414b2ca 100644 --- a/sources/shiboken6/cmake/ShibokenHelpers.cmake +++ b/sources/shiboken6/cmake/ShibokenHelpers.cmake @@ -869,28 +869,9 @@ endfunction() # Get path to libclang.dll/libclang.so depending on the platform macro(find_libclang) - if(CMAKE_HOST_WIN32) - set(libclang_directory_suffix "bin") - set(libclang_suffix ".dll") - else() - set(libclang_directory_suffix "lib") - if(CMAKE_HOST_APPLE) - set(libclang_suffix ".dylib") - else() - set(libclang_suffix ".so") - endif() - endif() - - set(libclang_lib_dir "") - if(DEFINED ENV{LLVM_INSTALL_DIR}) - set(libclang_lib_dir "$ENV{LLVM_INSTALL_DIR}/${libclang_directory_suffix}") - elseif(DEFINED ENV{CLANG_INSTALL_DIR}) - set(libclang_lib_dir "$ENV{CLANG_INSTALL_DIR}/${libclang_directory_suffix}") - else() - message(WARNING - "Couldn't find libclang${libclang_suffix} " - "You will likely need to add it manually to PATH to ensure the build succeeds.") - endif() + find_package(Clang CONFIG REQUIRED) + get_target_property(libclang_location libclang LOCATION) + get_filename_component(libclang_lib_dir "${libclang_location}" DIRECTORY) endmacro() # Allow setting a shiboken debug level from the the build system or from the environment diff --git a/sources/shiboken6/doc/typesystem_conversionrule.rst b/sources/shiboken6/doc/typesystem_conversionrule.rst index cee45bfb3..f6ce18345 100644 --- a/sources/shiboken6/doc/typesystem_conversionrule.rst +++ b/sources/shiboken6/doc/typesystem_conversionrule.rst @@ -12,9 +12,13 @@ The **conversion-rule** tag specifies how a **primitive-type**, a **container-ty or a **value-type** may be converted to and from the native C++ language types to the target language types (see also :ref:`user-defined-type-conversion`). -It is a child of the :ref:`container-type`, :ref:`primitive-type` or -:ref:`value-type` and may contain :ref:`native-to-target` or -:ref:`native-to-target` child nodes. +It may be a child of the :ref:`container-type` and :ref:`primitive-type` nodes, +where conversions have to be provided for both directions using the +:ref:`native-to-target` and :ref:`target-to-native` child nodes. + +It may also appear as a child of :ref:`value-type` or :ref:`smart-pointer-type` +where additional conversions from other target language types can be provided +using the :ref:`target-to-native` child node. .. code-block:: xml @@ -70,8 +74,9 @@ an input value an does what's needed to convert it to the output value. </conversion-rule> Use the replace node to modify the template code. -Notice that the generator must provide type system variables for the input -and output values and types, namely **%in**, **%out**, **%INTYPE** and +Notice that the generator provides type system variables for the input +and output values and types (see :ref:`converter_variables_and_functions`). +The most important ones are **%in**, **%out**, **%INTYPE** and **%OUTTYPE**. In the case of container types, **%INTYPE** refers to the full container type (e.g. **"list<int>"**) and **%INTYPE_0**, **%INTYPE_1**, **%INTYPE_#**, should be replaced by the types used in the container template diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst index 60ac5c6d9..798ef5719 100644 --- a/sources/shiboken6/doc/typesystem_specifying_types.rst +++ b/sources/shiboken6/doc/typesystem_specifying_types.rst @@ -729,7 +729,8 @@ The ``smart pointer`` type node indicates that the given class is a smart pointe and requires inserting calls to **getter** to access the pointeee. Currently, the usage is limited to function return values. **ref-count-method** specifies the name of the method used to do reference counting. -It is a child of the :ref:`typesystem_details` node or other type nodes. +It is a child of the :ref:`typesystem_details` node or other type nodes +and may contain :ref:`conversion-rule` nodes. The *optional* attribute **instantiations** specifies for which instantiations of the smart pointer wrappers will be generated (comma-separated list). diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp index 539094075..29603bd97 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp @@ -2120,6 +2120,24 @@ void CppGenerator::writeCustomConverterRegister(TextStream &s, } } +void CppGenerator::writeTemplateCustomConverterRegister(TextStream &s, + const AbstractMetaType &type, + QString converter) +{ + auto customConversion = CustomConversion::getCustomConversion(type.typeEntry()); + if (!customConversion || customConversion->targetToNativeConversions().isEmpty()) + return; + if (converter.isEmpty()) + converter = converterVar; + const QString typeName = fixedCppTypeName(type); + for (const auto &conv : customConversion->targetToNativeConversions()) { + const QString &sourceTypeName = conv.sourceTypeName(); + QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName); + QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName); + writeAddPythonToCppConversion(s, converter, toCpp, isConv); + } +} + void CppGenerator::writeContainerConverterFunctions(TextStream &s, const AbstractMetaType &containerType) const { @@ -3577,14 +3595,7 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, writePythonToCppFunction(s, code, sourceTypeName, targetTypeName); // Python to C++ convertible check function. - QString typeCheck = toNative.sourceTypeCheck(); - if (typeCheck.isEmpty()) { - QString pyTypeName = toNative.sourceTypeName(); - if (pyTypeName == u"Py_None" || pyTypeName == u"PyNone") - typeCheck = u"%in == Py_None"_s; - else if (pyTypeName == u"SbkObject") - typeCheck = u"Shiboken::Object::checkType(%in)"_s; - } + QString typeCheck = toNative.sourceTypeCheckFallback(); if (typeCheck.isEmpty()) { if (!toNative.sourceType() || toNative.sourceType()->isPrimitive()) { QString m; @@ -3595,33 +3606,47 @@ void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, typeCheck = u"PyObject_TypeCheck(%in, "_s + cpythonTypeNameExt(toNative.sourceType()) + u')'; } - typeCheck.replace(u"%in"_s, u"pyIn"_s); - processCodeSnip(typeCheck, targetType->qualifiedCppName()); + processTypeCheckCodeSnip(typeCheck, targetType->qualifiedCppName()); writeIsPythonConvertibleToCppFunction(s, sourceTypeName, targetTypeName, typeCheck); } -void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, const AbstractMetaType &containerType) const +void CppGenerator::writePythonToCppConversionFunctions(TextStream &s, + const AbstractMetaType &templateType) const { - Q_ASSERT(containerType.typeEntry()->isContainer()); - const auto cte = std::static_pointer_cast<const ContainerTypeEntry>(containerType.typeEntry()); - const auto customConversion = cte->customConversion(); - for (const auto &conv : customConversion->targetToNativeConversions()) - writePythonToCppConversionFunction(s, containerType, conv); + const auto customConversion = CustomConversion::getCustomConversion(templateType.typeEntry()); + if (customConversion) { + const auto &conversions = customConversion->targetToNativeConversions(); + for (const auto &conv : conversions) + writePythonToCppConversionFunction(s, templateType, conv); + } } void CppGenerator::writePythonToCppConversionFunction(TextStream &s, - const AbstractMetaType &containerType, + const AbstractMetaType &templateType, const TargetToNativeConversion &conv) const { + // Python to C++ convertible check function. + QString typeName = fixedCppTypeName(templateType); + // Check fallback is too broad for containers that need elements of same type + QString typeCheck = templateType.isContainer() + ? conv.sourceTypeCheck() : conv.sourceTypeCheckFallback(); + if (typeCheck.isEmpty()) { + typeCheck = cpythonCheckFunction(templateType); + if (typeCheck.isEmpty()) + typeCheck = u"false"_s; + else + typeCheck = typeCheck + u"pyIn)"_s; + } + // Python to C++ conversion function. - QString cppTypeName = getFullTypeNameWithoutModifiers(containerType); + QString cppTypeName = getFullTypeNameWithoutModifiers(templateType); QString code = conv.conversion(); const QString line = u"auto &cppOutRef = *reinterpret_cast<"_s + cppTypeName + u" *>(cppOut);"_s; CodeSnipAbstract::prependCode(&code, line); - for (qsizetype i = 0; i < containerType.instantiations().size(); ++i) { - const AbstractMetaType &type = containerType.instantiations().at(i); - QString typeName = getFullTypeName(type); + for (qsizetype i = 0; i < templateType.instantiations().size(); ++i) { + const AbstractMetaType &type = templateType.instantiations().at(i); + QString instTypeName = getFullTypeName(type); // Containers of opaque containers are not handled here. const auto generatorArg = GeneratorArgument::fromMetaType(type); if (generatorArg.indirections > 0 && !type.generateOpaqueContainer()) { @@ -3635,23 +3660,19 @@ void CppGenerator::writePythonToCppConversionFunction(TextStream &s, rightCode.replace(varName, u'*' + varName); code.replace(pos, code.size() - pos, rightCode); } - typeName.append(u" *"_s); + instTypeName.append(" *"_L1); } - code.replace(u"%OUTTYPE_"_s + QString::number(i), typeName); + const QString var = "%OUTTYPE_"_L1 + QString::number(i); + code.replace(var, instTypeName); + typeCheck.replace(var, instTypeName); } code.replace(u"%OUTTYPE"_s, cppTypeName); code.replace(u"%in"_s, u"pyIn"_s); code.replace(u"%out"_s, u"cppOutRef"_s); - QString typeName = fixedCppTypeName(containerType); const QString &sourceTypeName = conv.sourceTypeName(); writePythonToCppFunction(s, code, sourceTypeName, typeName); - // Python to C++ convertible check function. - QString typeCheck = cpythonCheckFunction(containerType); - if (typeCheck.isEmpty()) - typeCheck = u"false"_s; - else - typeCheck = typeCheck + u"pyIn)"_s; + processTypeCheckCodeSnip(typeCheck, typeName); // needs %OUTTYPE_[n] writeIsPythonConvertibleToCppFunction(s, sourceTypeName, typeName, typeCheck); s << '\n'; } @@ -4438,8 +4459,7 @@ QString CppGenerator::writeContainerConverterInitialization(TextStream &s, s << '&' << targetTypeName << "_Type"; } - const QString typeName = fixedCppTypeName(type); - s << ", " << cppToPythonFunctionName(typeName, targetTypeName) << ");\n"; + s << ", " << cppToPythonFunctionName(fixedCppTypeName(type), targetTypeName) << ");\n"; s << registerConverterName(cppSignature, converter); if (usePySideExtensions() && cppSignature.startsWith("const "_L1) @@ -4448,12 +4468,7 @@ QString CppGenerator::writeContainerConverterInitialization(TextStream &s, s << registerConverterName(underlyingType, converter); } - for (const auto &conv : typeEntry->customConversion()->targetToNativeConversions()) { - const QString &sourceTypeName = conv.sourceTypeName(); - QString toCpp = pythonToCppFunctionName(sourceTypeName, typeName); - QString isConv = convertibleToCppFunctionName(sourceTypeName, typeName); - writeAddPythonToCppConversion(s, converter, toCpp, isConv); - } + writeTemplateCustomConverterRegister(s, type, converter); auto typedefItPair = api.typedefTargetToName().equal_range(type.cppSignature()); if (typedefItPair.first != typedefItPair.second) { diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.h b/sources/shiboken6/generator/shiboken/cppgenerator.h index 0cf204234..1a192f8fd 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator.h +++ b/sources/shiboken6/generator/shiboken/cppgenerator.h @@ -114,6 +114,9 @@ private: static void writeCustomConverterRegister(TextStream &s, const CustomConversionPtr &customConversion, const QString &converterVar); + static void writeTemplateCustomConverterRegister(TextStream &s, + const AbstractMetaType &type, + QString converter = {}); void writeContainerConverterFunctions(TextStream &s, const AbstractMetaType &containerType) const; @@ -361,12 +364,13 @@ private: const TargetToNativeConversion &toNative, const TypeEntryCPtr &targetType) const; - /// Writes a pair of Python to C++ conversion and check functions for instantiated container types. + /// Writes a pair of Python to C++ conversion and check functions for instantiated + /// template (smart pointer/container types). void writePythonToCppConversionFunctions(TextStream &s, - const AbstractMetaType &containerType) const; + const AbstractMetaType &templateType) const; void writePythonToCppConversionFunction(TextStream &s, - const AbstractMetaType &containerType, + const AbstractMetaType &templateType, const TargetToNativeConversion &conv) const; static void writeAddPythonToCppConversion(TextStream &s, const QString &converterVar, diff --git a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp index 48c4ed5d2..1d3280e36 100644 --- a/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp +++ b/sources/shiboken6/generator/shiboken/cppgenerator_smartpointer.cpp @@ -232,13 +232,16 @@ void CppGenerator::generateSmartPointerClass(TextStream &s, void CppGenerator::writeSmartPointerConverterFunctions(TextStream &s, const AbstractMetaType &smartPointerType) const { + auto smartPointerTypeEntry = + std::static_pointer_cast<const SmartPointerTypeEntry>(smartPointerType.typeEntry()); + + if (smartPointerTypeEntry->hasCustomConversion()) + writePythonToCppConversionFunctions(s, smartPointerType); + const auto baseClasses = findSmartPointeeBaseClasses(api(), smartPointerType); if (baseClasses.isEmpty()) return; - auto smartPointerTypeEntry = - std::static_pointer_cast<const SmartPointerTypeEntry>(smartPointerType.typeEntry()); - // TODO: Missing conversion to smart pointer pointer type: s << "// Register smartpointer conversion for all derived classes\n"; @@ -290,6 +293,8 @@ void CppGenerator::writeSmartPointerConverterInitialization(TextStream &s, writeAddPythonToCppConversion(s, targetConverter, toCpp, isConv); }; + writeTemplateCustomConverterRegister(s, type); + const auto classes = findSmartPointeeBaseClasses(api(), type); if (classes.isEmpty()) return; diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp index 5c67f20f0..872076754 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.cpp +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.cpp @@ -1387,6 +1387,12 @@ void ShibokenGenerator::processClassCodeSnip(QString &code, const GeneratorConte processCodeSnip(code, context.effectiveClassName()); } +void ShibokenGenerator::processTypeCheckCodeSnip(QString &code, const QString &context) const +{ + code.replace("%in"_L1, "pyIn"_L1); + processCodeSnip(code, context); +} + void ShibokenGenerator::processCodeSnip(QString &code) const { // replace "toPython" converters diff --git a/sources/shiboken6/generator/shiboken/shibokengenerator.h b/sources/shiboken6/generator/shiboken/shibokengenerator.h index 045581ed6..c0f388871 100644 --- a/sources/shiboken6/generator/shiboken/shibokengenerator.h +++ b/sources/shiboken6/generator/shiboken/shibokengenerator.h @@ -161,6 +161,8 @@ protected: void processCodeSnip(QString &code) const; void processCodeSnip(QString &code, const QString &context) const; void processClassCodeSnip(QString &code, const GeneratorContext &context) const; + /// Replaces variables in a custom conversion type check snippet + void processTypeCheckCodeSnip(QString &code, const QString &context) const; /** * Verifies if any of the function's code injections makes a call diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 2bb3c9a87..84cb15feb 100644 --- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -509,6 +509,7 @@ def init_PySide6_QtCore(): "PySide6.QtCore.QUrl.ComponentFormattingOptions": PySide6.QtCore.QUrl.ComponentFormattingOption, # mismatch option/enum, why??? "PyUnicode": typing.Text, + "QByteArray": typing.Union[PySide6.QtCore.QByteArray, bytes, bytearray, memoryview], "QByteArrayView": PySide6.QtCore.QByteArray, "Q_NULLPTR": None, "QCalendar.Unspecified": PySide6.QtCore.QCalendar.Unspecified, diff --git a/sources/shiboken6/tests/smartbinding/std_optional_test.py b/sources/shiboken6/tests/smartbinding/std_optional_test.py index cd97facfa..9e8bc8d47 100644 --- a/sources/shiboken6/tests/smartbinding/std_optional_test.py +++ b/sources/shiboken6/tests/smartbinding/std_optional_test.py @@ -26,6 +26,15 @@ def integer_from_value(v): class StdOptionalTests(unittest.TestCase): + def testConversionFromInt(self): + """PYSIDE-3107: Test whether a parameter taking a 'std::optional<int>' + accepts 'int'.""" + b = StdOptionalTestBench() + b.setOptionalInt(43) + self.assertEqual(b.optionalInt().value(), 43) + b.setOptionalInt(None) + self.assertFalse(b.optionalInt().has_value()) + def testCInt(self): b = StdOptionalTestBench() ci = b.optionalInt() diff --git a/sources/shiboken6/tests/smartbinding/typesystem_smart.xml b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml index 14b181b61..4024036fa 100644 --- a/sources/shiboken6/tests/smartbinding/typesystem_smart.xml +++ b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml @@ -50,6 +50,19 @@ value-check-method="has_value" instantiations="Integer,int"> <include file-name="optional" location="global"/> + <!-- PYSIDE-3107: Generic rule constructing std::optional<T>' from 'T'. --> + <conversion-rule> + <target-to-native> + <add-conversion type="Py_None"> + SBK_UNUSED(pyIn) + %out = std::nullopt; + </add-conversion> + <add-conversion type="InstType" check="%CHECKTYPE[%OUTTYPE_0](%in)"> + %OUTTYPE_0 v = %CONVERTTOCPP[%OUTTYPE_0](%in); + %out = %OUTTYPE(v); + </add-conversion> + </target-to-native> + </conversion-rule> </smart-pointer-type> </namespace-type> diff --git a/testing/wheel_tester.py b/testing/wheel_tester.py index 0f6fb04ff..e5b47ffc1 100644 --- a/testing/wheel_tester.py +++ b/testing/wheel_tester.py @@ -84,10 +84,10 @@ def package_prefix_names(): # Note: shiboken6_generator is not needed for compile_using_nuitka, # but building modules with cmake needs it. if NEW_WHEELS: - return ["shiboken6", "shiboken6_generator", "PySide6_Essentials", "PySide6_Addons", - "PySide6"] + return ["shiboken6", "shiboken6_generator", "pyside6_essentials", "pyside6_addons", + "pyside6"] else: - return ["shiboken6", "shiboken6_generator", "PySide6"] + return ["shiboken6", "shiboken6_generator", "pyside6"] def clean_egg_info(): |