From 8f029e551fbb8570ba30af65a92bcb3586c3af47 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Tue, 23 Jan 2024 07:44:50 +0100 Subject: [PATCH] Gui: PythonWrapper: consolidate module loader --- src/Gui/PythonWrapper.cpp | 255 +++++++++++++++++++------------------- src/Gui/PythonWrapper.h | 4 - 2 files changed, 128 insertions(+), 131 deletions(-) diff --git a/src/Gui/PythonWrapper.cpp b/src/Gui/PythonWrapper.cpp index 7a230bb30d..0123e339bd 100644 --- a/src/Gui/PythonWrapper.cpp +++ b/src/Gui/PythonWrapper.cpp @@ -71,40 +71,27 @@ // #ifdef HAVE_SHIBOKEN2 # define HAVE_SHIBOKEN -# undef _POSIX_C_SOURCE -# undef _XOPEN_SOURCE -# include -# include -# include -# include # ifdef HAVE_PYSIDE2 -# define HAVE_PYSIDE +# define HAVE_PYSIDE // Since version 5.12 shiboken offers a method to get wrapper by class name (typeForTypeName) // This helps to avoid to include the PySide2 headers since MSVC has a compiler bug when // compiling together with std::bitset (https://bugreports.qt.io/browse/QTBUG-72073) // Do not use SHIBOKEN_MICRO_VERSION; it might contain a dot -# define SHIBOKEN_FULL_VERSION QT_VERSION_CHECK(SHIBOKEN_MAJOR_VERSION, SHIBOKEN_MINOR_VERSION, 0) -# if (SHIBOKEN_FULL_VERSION >= QT_VERSION_CHECK(5, 12, 0)) -# define HAVE_SHIBOKEN_TYPE_FOR_TYPENAME -# endif +# define SHIBOKEN_FULL_VERSION QT_VERSION_CHECK(SHIBOKEN_MAJOR_VERSION, SHIBOKEN_MINOR_VERSION, 0) +# if (SHIBOKEN_FULL_VERSION >= QT_VERSION_CHECK(5, 12, 0)) +# define HAVE_SHIBOKEN_TYPE_FOR_TYPENAME +# endif -# ifndef HAVE_SHIBOKEN_TYPE_FOR_TYPENAME -# include -# include -# include -# endif -# include -PyTypeObject** SbkPySide2_QtCoreTypes = nullptr; -PyTypeObject** SbkPySide2_QtGuiTypes = nullptr; -PyTypeObject** SbkPySide2_QtWidgetsTypes = nullptr; -PyTypeObject** SbkPySide2_QtPrintSupportTypes = nullptr; -PyTypeObject** SbkPySide2_QtUiToolsTypes = nullptr; +# ifndef HAVE_SHIBOKEN_TYPE_FOR_TYPENAME +# include +# include +# include +# endif # endif // HAVE_PYSIDE2 #endif // HAVE_SHIBOKEN2 - //----------------------------------------------------------------------------- // // shiboken6 and PySide6 specific defines and includes @@ -114,24 +101,26 @@ PyTypeObject** SbkPySide2_QtUiToolsTypes = nullptr; // #ifdef HAVE_SHIBOKEN6 # define HAVE_SHIBOKEN +# ifdef HAVE_PYSIDE6 +# define HAVE_PYSIDE +# define HAVE_SHIBOKEN_TYPE_FOR_TYPENAME +# endif // HAVE_PYSIDE6 +#endif // HAVE_SHIBOKEN6 + +//----------------------------------------------------------------------------- + +#ifdef HAVE_SHIBOKEN # undef _POSIX_C_SOURCE # undef _XOPEN_SOURCE # include # include # include # include -# ifdef HAVE_PYSIDE6 -# define HAVE_PYSIDE -# define HAVE_SHIBOKEN_TYPE_FOR_TYPENAME -# include -PyTypeObject** SbkPySide6_QtCoreTypes = nullptr; -PyTypeObject** SbkPySide6_QtGuiTypes = nullptr; -PyTypeObject** SbkPySide6_QtWidgetsTypes = nullptr; -PyTypeObject** SbkPySide6_QtPrintSupportTypes = nullptr; -PyTypeObject** SbkPySide6_QtUiToolsTypes = nullptr; -# endif // HAVE_PYSIDE6 -#endif // HAVE_SHIBOKEN6 +#endif // HAVE_SHIBOKEN +#ifdef HAVE_PYSIDE +# include +#endif // HAVE_PYSIDE //----------------------------------------------------------------------------- @@ -156,6 +145,49 @@ PyTypeObject** SbkPySide6_QtUiToolsTypes = nullptr; #include "UiLoader.h" #include "MetaTypes.h" +#ifdef HAVE_SHIBOKEN +#ifdef HAVE_SHIBOKEN2 +PyTypeObject** SbkPySide2_QtCoreTypes = nullptr; +PyTypeObject** SbkPySide2_QtGuiTypes = nullptr; +PyTypeObject** SbkPySide2_QtWidgetsTypes = nullptr; +PyTypeObject** SbkPySide2_QtPrintSupportTypes = nullptr; +PyTypeObject** SbkPySide2_QtUiToolsTypes = nullptr; +constexpr auto &SbkPySide_QtCoreTypes = SbkPySide2_QtCoreTypes; +constexpr auto &SbkPySide_QtGuiTypes = SbkPySide2_QtGuiTypes; +constexpr auto &SbkPySide_QtWidgetsTypes = SbkPySide2_QtWidgetsTypes; +constexpr auto &SbkPySide_QtPrintSupportTypes = SbkPySide2_QtPrintSupportTypes; +constexpr auto &SbkPySide_QtUiToolsTypes = SbkPySide2_QtUiToolsTypes; +constexpr const char* ModuleShiboken = "shiboken2"; +constexpr const char* ModulePySide = "PySide2"; +#else +PyTypeObject** SbkPySide6_QtCoreTypes = nullptr; +PyTypeObject** SbkPySide6_QtGuiTypes = nullptr; +PyTypeObject** SbkPySide6_QtWidgetsTypes = nullptr; +PyTypeObject** SbkPySide6_QtPrintSupportTypes = nullptr; +PyTypeObject** SbkPySide6_QtUiToolsTypes = nullptr; +constexpr auto &SbkPySide_QtCoreTypes = SbkPySide6_QtCoreTypes; +constexpr auto &SbkPySide_QtGuiTypes = SbkPySide6_QtGuiTypes; +constexpr auto &SbkPySide_QtWidgetsTypes = SbkPySide6_QtWidgetsTypes; +constexpr auto &SbkPySide_QtPrintSupportTypes = SbkPySide6_QtPrintSupportTypes; +constexpr auto &SbkPySide_QtUiToolsTypes = SbkPySide6_QtUiToolsTypes; +constexpr const char* ModuleShiboken = "shiboken6"; +constexpr const char* ModulePySide = "PySide6"; +#endif +#else +static PyTypeObject** SbkPySide_DummyTypes; +constexpr auto &SbkPySide_QtCoreTypes = SbkPySide_DummyTypes; +constexpr auto &SbkPySide_QtGuiTypes = SbkPySide_DummyTypes; +constexpr auto &SbkPySide_QtWidgetsTypes = SbkPySide_DummyTypes; +constexpr auto &SbkPySide_QtPrintSupportTypes = SbkPySide_DummyTypes; +constexpr auto &SbkPySide_QtUiToolsTypes = SbkPySide_DummyTypes; +# if QT_VERSION < QT_VERSION_CHECK(6,0,0) +constexpr const char* ModuleShiboken = "shiboken2"; +constexpr const char* ModulePySide = "PySide2"; +# else +constexpr const char* ModuleShiboken = "shiboken6"; +constexpr const char* ModulePySide = "PySide6"; +# endif +#endif using namespace Gui; @@ -338,49 +370,62 @@ private: ~WrapperManager() override = default; }; -static std::string formatModuleError(std::string name) +static std::string formatModuleError(const std::string& name) { std::string error = "Cannot load " + name + " module"; - PyErr_Print(); return error; } +static std::string getPySideModuleName(const std::string& moduleName) +{ + std::string name(ModulePySide); + name += '.'; + name += moduleName; + + return name; +} + +static PyObject* importShiboken() +{ + PyObject* obj = PyImport_ImportModule(ModuleShiboken); + if (obj) { + return obj; + } + + throw Py::Exception(PyExc_ImportError, formatModuleError(ModuleShiboken)); +} + +static PyObject* importPySide(const std::string& moduleName) +{ + std::string name = getPySideModuleName(moduleName); + PyObject* obj = PyImport_ImportModule(name.c_str()); + if (obj) { + return obj; + } + + throw Py::Exception(PyExc_ImportError, formatModuleError(name)); +} + template Py::Object qt_wrapInstance(qttype object, const std::string& className, - const std::string& shiboken, - const std::string& pyside, + const std::string& moduleName, const std::string& wrap) { - PyObject* module = PyImport_ImportModule(shiboken.c_str()); - if (!module) { - throw Py::Exception(PyExc_ImportError, formatModuleError(shiboken)); - } - - Py::Module mainmod(module, true); + Py::Module mainmod(importShiboken(), true); Py::Callable func = mainmod.getDict().getItem(wrap); Py::Tuple arguments(2); arguments[0] = Py::asObject(PyLong_FromVoidPtr((void*)object)); - module = PyImport_ImportModule(pyside.c_str()); - if (!module) { - throw Py::Exception(PyExc_ImportError, formatModuleError(pyside)); - } - - Py::Module qtmod(module); + Py::Module qtmod(importPySide(moduleName)); arguments[1] = qtmod.getDict().getItem(className); return func.apply(arguments); } -const char* qt_identifyType(QObject* ptr, const std::string& pyside) +const char* qt_identifyType(QObject* ptr, const std::string& moduleName) { - PyObject* module = PyImport_ImportModule(pyside.c_str()); - if (!module) { - throw Py::Exception(PyExc_ImportError, formatModuleError(pyside)); - } - - Py::Module qtmod(module); + Py::Module qtmod(importPySide(moduleName)); const QMetaObject* metaObject = ptr->metaObject(); while (metaObject) { const char* className = metaObject->className(); @@ -392,22 +437,16 @@ const char* qt_identifyType(QObject* ptr, const std::string& pyside) return nullptr; } -void* qt_getCppPointer(const Py::Object& pyobject, const std::string& shiboken, const std::string& unwrap) +void* qt_getCppPointer(const Py::Object& pyobject, const std::string& unwrap) { // https://github.com/PySide/Shiboken/blob/master/shibokenmodule/typesystem_shiboken.xml - PyObject* module = PyImport_ImportModule(shiboken.c_str()); - if (!module) { - throw Py::Exception(PyExc_ImportError, formatModuleError(shiboken)); - } - - Py::Module mainmod(module, true); + Py::Module mainmod(importShiboken(), true); Py::Callable func = mainmod.getDict().getItem(unwrap); Py::Tuple arguments(1); arguments[0] = pyobject; //PySide pointer Py::Tuple result(func.apply(arguments)); - void* ptr = PyLong_AsVoidPtr(result[0].ptr()); - return ptr; + return PyLong_AsVoidPtr(result[0].ptr()); } @@ -431,10 +470,9 @@ PyTypeObject *getPyTypeObjectForTypeName() } template -qttype* qt_getCppType(PyObject* pyobj, const std::string& shiboken) +qttype* qt_getCppType(PyObject* pyobj) { #if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) - Q_UNUSED(shiboken) PyTypeObject * type = getPyTypeObjectForTypeName(); if (type) { if (Shiboken::Object::checkType(pyobj)) { @@ -444,19 +482,18 @@ qttype* qt_getCppType(PyObject* pyobj, const std::string& shiboken) } } #else - void* ptr = qt_getCppPointer(Py::asObject(pyobj), shiboken, "getCppPointer"); + void* ptr = qt_getCppPointer(Py::asObject(pyobj), "getCppPointer"); if (ptr) return reinterpret_cast(ptr); #endif - return nullptr; } -bool loadPySideModule(const std::string& moduleName, PyTypeObject**& types) +static bool loadPySideModule(const std::string& moduleName, PyTypeObject**& types) { #if defined (HAVE_SHIBOKEN) && defined(HAVE_PYSIDE) if (!types) { - Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(moduleName.c_str())); + Shiboken::AutoDecRef requiredModule(Shiboken::Module::import(getPySideModuleName(moduleName).c_str())); if (requiredModule.isNull()) return false; types = Shiboken::Module::getTypes(requiredModule); @@ -472,21 +509,10 @@ bool loadPySideModule(const std::string& moduleName, PyTypeObject**& types) // -------------------------------------------------------- -#ifdef HAVE_SHIBOKEN6 -std::string PythonWrapper::shiboken{"shiboken6"}; -std::string PythonWrapper::PySide{"PySide6"}; -#elif HAVE_SHIBOKEN2 -std::string PythonWrapper::shiboken{"shiboken2"}; -std::string PythonWrapper::PySide{"PySide2"}; -#else -std::string PythonWrapper::shiboken{"shiboken"}; -std::string PythonWrapper::PySide{"PySide"}; -#endif - PythonWrapper::PythonWrapper() { #if defined (HAVE_SHIBOKEN) - static bool init = false; + static bool init; if (!init) { init = true; registerTypes(); @@ -518,12 +544,12 @@ bool PythonWrapper::toCString(const Py::Object& pyobject, std::string& str) QObject* PythonWrapper::toQObject(const Py::Object& pyobject) { - return qt_getCppType(pyobject.ptr(), shiboken); + return qt_getCppType(pyobject.ptr()); } QGraphicsItem* PythonWrapper::toQGraphicsItem(PyObject* pyPtr) { - return qt_getCppType(pyPtr, shiboken); + return qt_getCppType(pyPtr); } QGraphicsItem* PythonWrapper::toQGraphicsItem(const Py::Object& pyobject) @@ -533,7 +559,7 @@ QGraphicsItem* PythonWrapper::toQGraphicsItem(const Py::Object& pyobject) QGraphicsObject* PythonWrapper::toQGraphicsObject(PyObject* pyPtr) { - return qt_getCppType(pyPtr, shiboken); + return qt_getCppType(pyPtr); } QGraphicsObject* PythonWrapper::toQGraphicsObject(const Py::Object& pyobject) @@ -557,14 +583,14 @@ Py::Object PythonWrapper::fromQImage(const QImage& img) #else // Access shiboken/PySide via Python // - return qt_wrapInstance(&img, "QImage", shiboken, PySide + ".QtGui", "wrapInstance"); + return qt_wrapInstance(&img, "QImage", "QtGui", "wrapInstance"); #endif throw Py::RuntimeError("Failed to wrap icon"); } QImage *PythonWrapper::toQImage(PyObject *pyobj) { - return qt_getCppType(pyobj, shiboken); + return qt_getCppType(pyobj); } Py::Object PythonWrapper::fromQIcon(const QIcon* icon) @@ -583,14 +609,14 @@ Py::Object PythonWrapper::fromQIcon(const QIcon* icon) #else // Access shiboken/PySide via Python // - return qt_wrapInstance(icon, "QIcon", shiboken, PySide + ".QtGui", "wrapInstance"); + return qt_wrapInstance(icon, "QIcon", "QtGui", "wrapInstance"); #endif throw Py::RuntimeError("Failed to wrap icon"); } QIcon *PythonWrapper::toQIcon(PyObject *pyobj) { - return qt_getCppType(pyobj, shiboken); + return qt_getCppType(pyobj); } Py::Object PythonWrapper::fromQDir(const QDir& dir) @@ -614,7 +640,7 @@ Py::Object PythonWrapper::fromQDir(const QDir& dir) QDir* PythonWrapper::toQDir(PyObject* pyobj) { - return qt_getCppType(pyobj, shiboken); + return qt_getCppType(pyobj); } Py::Object PythonWrapper::fromQPrinter(QPrinter* printer) @@ -642,7 +668,7 @@ Py::Object PythonWrapper::fromQPrinter(QPrinter* printer) #else // Access shiboken/PySide via Python // - return qt_wrapInstance(printer, "QPrinter", shiboken, PySide + ".QtCore", "wrapInstance"); + return qt_wrapInstance(printer, "QPrinter", "QtCore", "wrapInstance"); #endif } @@ -673,7 +699,7 @@ Py::Object PythonWrapper::fromQObject(QObject* object, const char* className) #else // Access shiboken/PySide via Python // - return qt_wrapInstance(object, className, shiboken, PySide + ".QtCore", "wrapInstance"); + return qt_wrapInstance(object, className, "QtCore", "wrapInstance"); #endif } @@ -703,7 +729,7 @@ Py::Object PythonWrapper::fromQWidget(QWidget* widget, const char* className) #else // Access shiboken/PySide via Python // - return qt_wrapInstance(widget, className, shiboken, PySide + ".QtWidgets", "wrapInstance"); + return qt_wrapInstance(widget, className, "QtWidgets", "wrapInstance"); #endif } @@ -734,52 +760,27 @@ const char* PythonWrapper::getWrapperName(QObject* obj) const bool PythonWrapper::loadCoreModule() { -#if defined (HAVE_SHIBOKEN2) && (HAVE_PYSIDE2) - return loadPySideModule(PySide + ".QtCore", SbkPySide2_QtCoreTypes); -#elif defined (HAVE_SHIBOKEN6) && (HAVE_PYSIDE6) - return loadPySideModule(PySide + ".QtCore", SbkPySide6_QtCoreTypes); -#endif - return true; + return loadPySideModule("QtCore", SbkPySide_QtCoreTypes); } bool PythonWrapper::loadGuiModule() { -#if defined (HAVE_SHIBOKEN2) && defined(HAVE_PYSIDE2) - return loadPySideModule(PySide + ".QtGui", SbkPySide2_QtGuiTypes); -#elif defined (HAVE_SHIBOKEN6) && defined(HAVE_PYSIDE6) - return loadPySideModule(PySide + ".QtGui", SbkPySide6_QtGuiTypes); -#endif - return true; + return loadPySideModule("QtGui", SbkPySide_QtGuiTypes); } bool PythonWrapper::loadWidgetsModule() { -#if defined (HAVE_SHIBOKEN2) && defined(HAVE_PYSIDE2) - return loadPySideModule(PySide + ".QtWidgets", SbkPySide2_QtWidgetsTypes); -#elif defined (HAVE_SHIBOKEN6) && defined(HAVE_PYSIDE6) - return loadPySideModule(PySide + ".QtWidgets", SbkPySide6_QtWidgetsTypes); -#endif - return true; + return loadPySideModule("QtWidgets", SbkPySide_QtWidgetsTypes); } bool PythonWrapper::loadPrintSupportModule() { -#if defined (HAVE_SHIBOKEN2) && defined(HAVE_PYSIDE2) - return loadPySideModule(PySide + ".QtPrintSupport", SbkPySide2_QtPrintSupportTypes); -#elif defined (HAVE_SHIBOKEN6) && defined(HAVE_PYSIDE6) - return loadPySideModule(PySide + ".QtPrintSupport", SbkPySide6_QtPrintSupportTypes); -#endif - return true; + return loadPySideModule("QtPrintSupport", SbkPySide_QtPrintSupportTypes); } bool PythonWrapper::loadUiToolsModule() { -#if defined (HAVE_SHIBOKEN2) && defined(HAVE_PYSIDE2) - return loadPySideModule(PySide + ".QtUiTools", SbkPySide2_QtUiToolsTypes); -#elif defined (HAVE_SHIBOKEN6) && defined(HAVE_PYSIDE6) - return loadPySideModule(PySide + ".QtUiTools", SbkPySide6_QtUiToolsTypes); -#endif - return true; + return loadPySideModule("QtUiTools", SbkPySide_QtUiToolsTypes); } void PythonWrapper::createChildrenNameAttributes(PyObject* root, QObject* object) @@ -798,7 +799,7 @@ void PythonWrapper::createChildrenNameAttributes(PyObject* root, QObject* object #endif PyObject_SetAttrString(root, name.constData(), pyChild); #else - const char* className = qt_identifyType(child, PySide + ".QtWidgets"); + const char* className = qt_identifyType(child, "QtWidgets"); if (!className) { if (qobject_cast(child)) className = "QWidget"; @@ -806,7 +807,7 @@ void PythonWrapper::createChildrenNameAttributes(PyObject* root, QObject* object className = "QObject"; } - Py::Object pyChild(qt_wrapInstance(child, className, shiboken, PySide + ".QtWidgets", "wrapInstance")); + Py::Object pyChild(qt_wrapInstance(child, className, "QtWidgets", "wrapInstance")); PyObject_SetAttrString(root, name.constData(), pyChild.ptr()); #endif } diff --git a/src/Gui/PythonWrapper.h b/src/Gui/PythonWrapper.h index 8326d69e39..b854ae3fa9 100644 --- a/src/Gui/PythonWrapper.h +++ b/src/Gui/PythonWrapper.h @@ -75,10 +75,6 @@ public: QDir* toQDir(PyObject* pyobj); static void createChildrenNameAttributes(PyObject* root, QObject* object); static void setParent(PyObject* pyWdg, QObject* parent); - -private: - static std::string shiboken; - static std::string PySide; }; } // namespace Gui