diff options
Diffstat (limited to 'sources')
35 files changed, 267 insertions, 126 deletions
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/PySide6/QtCore/CMakeLists.txt b/sources/pyside6/PySide6/QtCore/CMakeLists.txt index d559f9d96..fff6cc8b0 100644 --- a/sources/pyside6/PySide6/QtCore/CMakeLists.txt +++ b/sources/pyside6/PySide6/QtCore/CMakeLists.txt @@ -19,9 +19,6 @@ if(ENABLE_WIN) set(SPECIFIC_OS_FILES ${QtCore_GEN_DIR}/qwineventnotifier_wrapper.cpp ) -else() - set(SPECIFIC_OS_FILES - ${QtCore_GEN_DIR}/qprocess_unixprocessparameters_wrapper.cpp) endif() set(QtCore_SRC @@ -130,8 +127,6 @@ ${QtCore_GEN_DIR}/qpersistentmodelindex_wrapper.cpp ${QtCore_GEN_DIR}/qpluginloader_wrapper.cpp ${QtCore_GEN_DIR}/qpoint_wrapper.cpp ${QtCore_GEN_DIR}/qpointf_wrapper.cpp -${QtCore_GEN_DIR}/qprocess_wrapper.cpp -${QtCore_GEN_DIR}/qprocessenvironment_wrapper.cpp ${QtCore_GEN_DIR}/qpropertyanimation_wrapper.cpp ${QtCore_GEN_DIR}/qrandomgenerator64_wrapper.cpp ${QtCore_GEN_DIR}/qrandomgenerator_wrapper.cpp @@ -236,6 +231,23 @@ else() list(APPEND QtCore_SRC ${QtCore_GEN_DIR}/qsharedmemory_wrapper.cpp) endif() +if("process" IN_LIST QtCore_disabled_features) + list(APPEND QtCore_DROPPED_ENTRIES QProcess) + message(STATUS "Qt${QT_MAJOR_VERSION}Core: Dropping QProcess") +else() + list(APPEND QtCore_SRC ${QtCore_GEN_DIR}/qprocess_wrapper.cpp) + if(NOT ENABLE_WIN) + list(APPEND QtCore_SRC ${QtCore_GEN_DIR}/qprocess_unixprocessparameters_wrapper.cpp) + endif() +endif() + +if("processenvironment" IN_LIST QtCore_disabled_features) + list(APPEND QtCore_DROPPED_ENTRIES QProcessEnvironment) + message(STATUS "Qt${QT_MAJOR_VERSION}Core: Dropping QProcessEnvironment") +else() + list(APPEND QtCore_SRC ${QtCore_GEN_DIR}/qprocessenvironment_wrapper.cpp) +endif() + configure_file("${QtCore_SOURCE_DIR}/QtCore_global.post.h.in" "${QtCore_BINARY_DIR}/QtCore_global.post.h" @ONLY) diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml index c3130ccb2..26c3ecab1 100644 --- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml +++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml @@ -2669,7 +2669,9 @@ <?if !windows?> <enum-type name="UnixProcessFlag" flags="UnixProcessFlags" since="6.6"/> - <value-type name="UnixProcessParameters" since="6.6"/> + <value-type name="UnixProcessParameters"> + <configuration condition="QT_CONFIG(process)"/> + </value-type> <?endif?> <modify-function signature="waitForStarted(int)" allow-thread="yes"/> diff --git a/sources/pyside6/cmake/PySideSetup.cmake b/sources/pyside6/cmake/PySideSetup.cmake index 45a63a1a0..a3bc1c738 100644 --- a/sources/pyside6/cmake/PySideSetup.cmake +++ b/sources/pyside6/cmake/PySideSetup.cmake @@ -246,6 +246,7 @@ ENDIF() set(GENERATOR_EXTRA_FLAGS ${SHIBOKEN_GENERATOR_EXTRA_FLAGS} ${debug_level} + "--platform=${CMAKE_SYSTEM_NAME}" ${UNOPTIMIZE} --generator-set=shiboken --enable-parent-ctor-heuristic 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/clangparser/clangbuilder.cpp b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp index 5188262de..81d7bd92f 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp @@ -827,6 +827,7 @@ BuilderPrivate::SpecialSystemHeader } switch (clang::platform()) { + case Platform::Linux: case Platform::Unix: if (fileName == u"/usr/include/stdlib.h" || baseName == u"types.h" diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp index 4d93a084f..f8bcf1244 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp +++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.cpp @@ -86,12 +86,18 @@ Platform platform() { return _platform; } bool setPlatform(const QString &name) { bool result = true; - if (name == u"windows") + if (name.compare("unix"_L1, Qt::CaseInsensitive) == 0) + _platform = Platform::Unix; + else if (name.compare("linux"_L1, Qt::CaseInsensitive) == 0) + _platform = Platform::Linux; + if (name.compare("windows"_L1, Qt::CaseInsensitive) == 0) _platform = Platform::Windows; - else if (name == u"darwin") + else if (name.compare("darwin"_L1, Qt::CaseInsensitive) == 0) _platform = Platform::macOS; - else if (name == u"unix") - _platform = Platform::Unix; + else if (name.compare("android"_L1, Qt::CaseInsensitive) == 0) + _platform = Platform::Android; + else if (name.compare("ios"_L1, Qt::CaseInsensitive) == 0) + _platform = Platform::iOS; else result = false; return result; diff --git a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h index 0e12ca137..2b1898a7e 100644 --- a/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h +++ b/sources/shiboken6/ApiExtractor/clangparser/compilersupport.h @@ -26,8 +26,11 @@ enum class Compiler { enum class Platform { Unix, + Linux, Windows, - macOS + macOS, + Android, + iOS }; namespace clang { diff --git a/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp b/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp index 6b9f0ae2e..88079a630 100644 --- a/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp +++ b/sources/shiboken6/ApiExtractor/conditionalstreamreader.cpp @@ -158,24 +158,7 @@ bool ConditionalStreamReader::conditionMatches() const void ConditionalStreamReader::setConditions(const QStringList &newConditions) { - m_conditions = newConditions + platformConditions(); -} - -QStringList ConditionalStreamReader::platformConditions() -{ - QStringList result; -#if defined (Q_OS_UNIX) - result << "unix"_L1; -#endif - -#if defined (Q_OS_LINUX) - result << "linux"_L1; -#elif defined (Q_OS_MACOS) - result << "darwin"_L1; -#elif defined (Q_OS_WINDOWS) - result << "windows"_L1; -#endif - return result; + m_conditions = newConditions; } ConditionalStreamReader::ExtendedToken ConditionalStreamReader::readNextInternal() diff --git a/sources/shiboken6/ApiExtractor/conditionalstreamreader.h b/sources/shiboken6/ApiExtractor/conditionalstreamreader.h index 36c4752a4..d9af5dc1e 100644 --- a/sources/shiboken6/ApiExtractor/conditionalstreamreader.h +++ b/sources/shiboken6/ApiExtractor/conditionalstreamreader.h @@ -69,8 +69,6 @@ public: const QStringList &conditions() const { return m_conditions; } void setConditions(const QStringList &newConditions); - static QStringList platformConditions(); - private: enum class PiTokens { None, If, Endif, EntityDefinition }; @@ -82,7 +80,7 @@ private: QXmlStreamReader m_reader; ProxyEntityResolver *m_proxyEntityResolver = nullptr; - QStringList m_conditions = ConditionalStreamReader::platformConditions(); + QStringList m_conditions; }; QDebug operator<<(QDebug dbg, const QXmlStreamAttributes &a); 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/docparser.cpp b/sources/shiboken6/ApiExtractor/docparser.cpp index 6fdabfa05..f3c51085a 100644 --- a/sources/shiboken6/ApiExtractor/docparser.cpp +++ b/sources/shiboken6/ApiExtractor/docparser.cpp @@ -22,10 +22,6 @@ #include "qtcompat.h" #include <cstdlib> -#ifdef HAVE_LIBXSLT -# include <libxslt/xsltutils.h> -# include <libxslt/transform.h> -#endif #include <algorithm> 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/typedatabase.cpp b/sources/shiboken6/ApiExtractor/typedatabase.cpp index b598258a6..ed2ea3ca6 100644 --- a/sources/shiboken6/ApiExtractor/typedatabase.cpp +++ b/sources/shiboken6/ApiExtractor/typedatabase.cpp @@ -6,6 +6,7 @@ #include "addedfunction.h" #include "messages.h" #include "typesystemparser_p.h" +#include "clangparser/compilersupport.h" #include "complextypeentry.h" #include "constantvaluetypeentry.h" #include "containertypeentry.h" @@ -433,10 +434,32 @@ void TypeDatabase::addRequiredTargetImport(const QString& moduleName) d->m_requiredTargetImports << moduleName; } +static QStringList platformKeywords() +{ + static constexpr auto unixKeyword = "unix"_L1; + static constexpr auto linuxKeyword = "linux"_L1; + switch (clang::platform()) { + case Platform::Unix: + return {unixKeyword}; + case Platform::Linux: + return {unixKeyword, linuxKeyword}; + case Platform::Windows: + return {"windows"_L1}; + case Platform::macOS: + return {unixKeyword, "darwin"_L1}; + case Platform::Android: + return {unixKeyword, linuxKeyword, "android"_L1}; + case Platform::iOS: + return {unixKeyword, "ios"_L1}; + } + return {}; +} + QStringList TypeDatabase::typesystemKeywords() const { - QStringList result = d->m_typesystemKeywords; - for (const auto &d : d->m_dropTypeEntries) + QStringList result = d->m_typesystemKeywords + platformKeywords(); + + for (const auto &d : std::as_const(d->m_dropTypeEntries)) result.append("no_"_L1 + d); switch (clang::emulatedCompilerLanguageLevel()) { 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/main.cpp b/sources/shiboken6/generator/main.cpp index fd395180c..892f1cf6b 100644 --- a/sources/shiboken6/generator/main.cpp +++ b/sources/shiboken6/generator/main.cpp @@ -193,8 +193,10 @@ bool CommonOptionsParser::handleOption(const QString &key, const QString &value, return true; } if (key == u"platform") { - if (!clang::setPlatform(value)) - throw Exception(u"Invalid value \""_s + value + u"\" passed to --platform"_s); + if (!clang::setPlatform(value)) { + qCWarning(lcShiboken, "Invalid value \"%s\" passed to --platform, defaulting to host.", + qPrintable(value)); + } return true; } 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/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp index 7616fa5c3..8c8f72241 100644 --- a/sources/shiboken6/generator/shiboken/headergenerator.cpp +++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp @@ -187,7 +187,7 @@ void HeaderGenerator::writeWrapperClass(TextStream &s, } s << "#include <sbkpython.h>\n\n#include <array>\n"; - s << "namespace Shiboken { class AutoDecRef; class GilState; }\n\n"; + s << "namespace Shiboken { struct AutoDecRef; class GilState; }\n\n"; if (usePySideExtensions() && isQObject(metaClass)) s << "namespace PySide { class DynamicQMetaObject; }\n\n"; 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/libshiboken/sbkbindingutils.h b/sources/shiboken6/libshiboken/sbkbindingutils.h index e40089ed2..4ed833dfa 100644 --- a/sources/shiboken6/libshiboken/sbkbindingutils.h +++ b/sources/shiboken6/libshiboken/sbkbindingutils.h @@ -8,7 +8,7 @@ #include "shibokenmacros.h" namespace Shiboken { -class AutoDecRef; +struct AutoDecRef; /// Maps a keyword argument by name to its parameter index struct ArgumentNameIndexMapping 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/CMakeLists.txt b/sources/shiboken6/tests/CMakeLists.txt index 05f6e9e60..37b80238f 100644 --- a/sources/shiboken6/tests/CMakeLists.txt +++ b/sources/shiboken6/tests/CMakeLists.txt @@ -23,7 +23,8 @@ else() message(STATUS "Tests will be generated using the protected hack!") set(GENERATOR_EXTRA_FLAGS ) endif() -list(APPEND GENERATOR_EXTRA_FLAGS ${SHIBOKEN_GENERATOR_EXTRA_FLAGS} ${debug_level}) +list(APPEND GENERATOR_EXTRA_FLAGS ${SHIBOKEN_GENERATOR_EXTRA_FLAGS} ${debug_level} + "--platform=${CMAKE_SYSTEM_NAME}") add_subdirectory(minimalbinding) if(NOT DEFINED MINIMAL_TESTS) 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> |