From bff242cfd8a34dcf2848a8864732eb5bdf85dbf0 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Sat, 1 Jun 2019 11:11:16 +0200 Subject: PySide: Allow any existing attribute in the constructor There are signals and properties which are correctly supported in PySide by the function "fillQtProperties". The structures are introspected by calling "QMetaObject::indexOfSignal" and "QMetaObject::indexOfProperty". By allowing any property, extending the above restriction, we break the Qt API slightly, but have the tremendous advantage of being able to write all needed properties into the constructor call. This approach is a compromize that keeps the attribute calls as they currently are. Supporting real properties where we actually have getter and setter functions would be possible as well, but that would break compatibility very much! It has to be discussed if we want to support a configuration switch that enables this incompatible change. If we would go this far, then I would do this together with changing mixedCase to lower_case. A simple test case has been added. Task-number: PYSIDE-1019 Change-Id: I8094df51d63aa767a5a9ec1c83bcf7db7b157a01 Reviewed-by: Qt CI Bot Reviewed-by: Cristian Maureira-Fredes --- sources/pyside2/libpyside/pyside.cpp | 55 +++++++++++++------ sources/pyside2/tests/pysidetest/CMakeLists.txt | 1 + .../pysidetest/constructor_properties_test.py | 64 ++++++++++++++++++++++ 3 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 sources/pyside2/tests/pysidetest/constructor_properties_test.py (limited to 'sources') diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 6e4a3efd4..170a3587f 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -94,6 +94,30 @@ void init(PyObject *module) SignalManager::instance(); } +static bool _setProperty(PyObject* qObj, PyObject *name, PyObject *value, bool *accept) +{ + QByteArray propName(Shiboken::String::toCString(name)); + propName[0] = std::toupper(propName[0]); + propName.prepend("set"); + + Shiboken::AutoDecRef propSetter(PyObject_GetAttrString(qObj, propName.constData())); + if (!propSetter.isNull()) { + *accept = true; + Shiboken::AutoDecRef args(PyTuple_Pack(1, value)); + Shiboken::AutoDecRef retval(PyObject_CallObject(propSetter, args)); + if (retval.isNull()) + return false; + } else { + Shiboken::AutoDecRef attr(PyObject_GenericGetAttr(qObj, name)); + if (PySide::Property::checkType(attr)) { + *accept = true; + if (PySide::Property::setValue(reinterpret_cast(attr.object()), qObj, value) < 0) + return false; + } + } + return true; +} + bool fillQtProperties(PyObject* qObj, const QMetaObject* metaObj, PyObject* kwds, const char** blackList, unsigned int blackListSize) { @@ -103,28 +127,27 @@ bool fillQtProperties(PyObject* qObj, const QMetaObject* metaObj, PyObject* kwds while (PyDict_Next(kwds, &pos, &key, &value)) { if (!blackListSize || !std::binary_search(blackList, blackList + blackListSize, std::string(Shiboken::String::toCString(key)))) { QByteArray propName(Shiboken::String::toCString(key)); + bool accept = false; if (metaObj->indexOfProperty(propName) != -1) { - propName[0] = std::toupper(propName[0]); - propName.prepend("set"); - - Shiboken::AutoDecRef propSetter(PyObject_GetAttrString(qObj, propName.constData())); - if (!propSetter.isNull()) { - Shiboken::AutoDecRef args(PyTuple_Pack(1, value)); - Shiboken::AutoDecRef retval(PyObject_CallObject(propSetter, args)); - } else { - PyObject* attr = PyObject_GenericGetAttr(qObj, key); - if (PySide::Property::checkType(attr)) - PySide::Property::setValue(reinterpret_cast(attr), qObj, value); - } + if (!_setProperty(qObj, key, value, &accept)) + return false; } else { propName.append("()"); if (metaObj->indexOfSignal(propName) != -1) { + accept = true; propName.prepend('2'); - PySide::Signal::connect(qObj, propName, value); - } else { - PyErr_Format(PyExc_AttributeError, "'%s' is not a Qt property or a signal", propName.constData()); + if (!PySide::Signal::connect(qObj, propName, value)) + return false; + } + } + if (!accept) { + // PYSIDE-1019: Allow any existing attribute in the constructor. + if (!_setProperty(qObj, key, value, &accept)) return false; - }; + } + if (!accept) { + PyErr_Format(PyExc_AttributeError, "'%S' is not a Qt property or a signal", key); + return false; } } } diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt index cb8ba04cf..3c993cf4e 100644 --- a/sources/pyside2/tests/pysidetest/CMakeLists.txt +++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt @@ -118,6 +118,7 @@ target_link_libraries(testbinding add_dependencies(testbinding pyside2 QtCore QtGui QtWidgets pysidetest) create_generator_target(testbinding) +PYSIDE_TEST(constructor_properties_test.py) PYSIDE_TEST(decoratedslot_test.py) # Will always crash when built against Qt 5.6, no point in running it. if (Qt5Core_VERSION VERSION_GREATER 5.7.0) diff --git a/sources/pyside2/tests/pysidetest/constructor_properties_test.py b/sources/pyside2/tests/pysidetest/constructor_properties_test.py new file mode 100644 index 000000000..48e2a7aae --- /dev/null +++ b/sources/pyside2/tests/pysidetest/constructor_properties_test.py @@ -0,0 +1,64 @@ +############################################################################# +## +## Copyright (C) 2019 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$ +## +############################################################################# + +import unittest + +from helper import UsesQApplication +from PySide2.QtCore import Qt +from PySide2.QtWidgets import QApplication, QLabel, QFrame + + +class ConstructorPropertiesTest(UsesQApplication): + + def testCallConstructor(self): + label = QLabel( + frameStyle=QFrame.Panel | QFrame.Sunken, + text="first line\nsecond line", + alignment=Qt.AlignBottom | Qt.AlignRight + ) + self.assertRaises(AttributeError, lambda: QLabel( + somethingelse=42, + text="first line\nsecond line", + alignment=Qt.AlignBottom | Qt.AlignRight + )) + + +if __name__ == '__main__': + unittest.main() + -- cgit v1.2.3 From 362f14ef730413869843dbb67745a3a9c4a6ec98 Mon Sep 17 00:00:00 2001 From: Julien Schueller Date: Tue, 28 May 2019 23:46:28 +0200 Subject: Shiboken: prune non-existent include Change-Id: I58f872d1e8abf2b624f37434c14e9ef6ea912749 Reviewed-by: Cristian Maureira-Fredes --- sources/shiboken2/ApiExtractor/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sources') diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt index c55dba973..6cc8cd583 100644 --- a/sources/shiboken2/ApiExtractor/CMakeLists.txt +++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt @@ -33,8 +33,7 @@ add_library(apiextractor STATIC ${apiextractor_SRC}) target_include_directories(apiextractor PRIVATE ${CLANG_EXTRA_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/parser - ${CMAKE_CURRENT_SOURCE_DIR}/parser/rpp) + ${CMAKE_CURRENT_SOURCE_DIR}/parser) target_link_libraries(apiextractor PUBLIC Qt5::Core) target_link_libraries(apiextractor PRIVATE ${CLANG_EXTRA_LIBRARIES}) -- cgit v1.2.3 From f54fc43bb466cb588cdb47edd08a86979d5b4e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simo=20F=C3=A4lt?= Date: Mon, 10 Jun 2019 14:12:14 +0300 Subject: Bump version strings to 5.12.4 Change-Id: If1386242c31e00412f289c9137c6a0427355ed9c Reviewed-by: Christian Tismer --- sources/pyside2/pyside_version.py | 2 +- sources/shiboken2/shiboken_version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sources') diff --git a/sources/pyside2/pyside_version.py b/sources/pyside2/pyside_version.py index c33b275f5..e253eb8fb 100644 --- a/sources/pyside2/pyside_version.py +++ b/sources/pyside2/pyside_version.py @@ -39,7 +39,7 @@ major_version = "5" minor_version = "12" -patch_version = "2" +patch_version = "4" # For example: "a", "b", "rc" # (which means "alpha", "beta", "release candidate"). diff --git a/sources/shiboken2/shiboken_version.py b/sources/shiboken2/shiboken_version.py index c33b275f5..e253eb8fb 100644 --- a/sources/shiboken2/shiboken_version.py +++ b/sources/shiboken2/shiboken_version.py @@ -39,7 +39,7 @@ major_version = "5" minor_version = "12" -patch_version = "2" +patch_version = "4" # For example: "a", "b", "rc" # (which means "alpha", "beta", "release candidate"). -- cgit v1.2.3 From 6108df521065e3a4628ae5656c3cbfd281b6765d Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Sun, 9 Jun 2019 17:13:28 +0200 Subject: Fix negative refcount on QSocketNotifier Change 43451e3bc17467593df64cb73ce8c0bf9e60045f from 2018-05-09 introduced a refcount bug that was not caught because we do not build with debug Python. This also revealed an omission in the patch "PySide: Allow any existing attribute in the constructor" when debug Python is used. Change-Id: Idbcbbc87f0a83bb696d03e05af0cf616b21f7335 Fixes: PYSIDE-1027 Reviewed-by: Friedemann Kleint Reviewed-by: Cristian Maureira-Fredes --- sources/pyside2/PySide2/glue/qtcore.cpp | 4 ++-- sources/pyside2/libpyside/pyside.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'sources') diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index fde016548..f30607f6b 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -1211,8 +1211,8 @@ QByteArray ba(1 + int(%2), char(0)); // @snippet qcryptographichash-adddata // @snippet qsocketnotifier -Shiboken::AutoDecRef socket(%PYARG_1); -if (!socket.isNull()) { +PyObject *socket = %PYARG_1; +if (socket != nullptr) { // We use qintptr as PyLong, but we check for int // since it is currently an alias to be Python2 compatible. // Internally, ints are qlonglongs. diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp index 170a3587f..fff28a9e7 100644 --- a/sources/pyside2/libpyside/pyside.cpp +++ b/sources/pyside2/libpyside/pyside.cpp @@ -108,6 +108,7 @@ static bool _setProperty(PyObject* qObj, PyObject *name, PyObject *value, bool * if (retval.isNull()) return false; } else { + PyErr_Clear(); Shiboken::AutoDecRef attr(PyObject_GenericGetAttr(qObj, name)); if (PySide::Property::checkType(attr)) { *accept = true; -- cgit v1.2.3 From 6371c1d419e9089226b3179031a9ee525033e2ea Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Wed, 16 Jan 2019 13:11:31 +0100 Subject: Complete the help() support for Types The help() support based upon the Signature module worked fine but for types. The reason was that the __signature__ module was a new attribute, while __doc__ already existed through an inheritance-like mechanism. When we add __doc__ later, the attributes are already in the cache. PyType_Modified(type) does not help in PySide. The solution was to add tp_getset to the metaclass SbkObjectType_Type which otherwise would have been reached from PyType_Type ('type' in Python). Note.. It makes sense to add the injected documentation to the __doc__ strings as well. This enables help output even with the py_doc web service! Task-number: PYSIDE-908 Change-Id: I09dd4bc6746ee41566a467604c4a68de5d66f94b Reviewed-by: Friedemann Kleint Reviewed-by: Cristian Maureira-Fredes Reviewed-by: Qt CI Bot --- sources/shiboken2/libshiboken/basewrapper.cpp | 10 ++++++++++ sources/shiboken2/libshiboken/signature.cpp | 20 ++++++++++++++++++++ sources/shiboken2/libshiboken/signature.h | 2 ++ 3 files changed, 32 insertions(+) (limited to 'sources') diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp index faaca5e4b..f38b55b56 100644 --- a/sources/shiboken2/libshiboken/basewrapper.cpp +++ b/sources/shiboken2/libshiboken/basewrapper.cpp @@ -76,11 +76,21 @@ extern "C" static void SbkObjectTypeDealloc(PyObject* pyObj); static PyObject* SbkObjectTypeTpNew(PyTypeObject* metatype, PyObject* args, PyObject* kwds); +// PYSIDE-908: The function PyType_Modified does not work in PySide, so we need to +// explicitly pass __doc__. For __signature__ it _did_ actually work, because +// it was not existing before. We add them both for clarity. +static PyGetSetDef SbkObjectType_Type_getsetlist[] = { + {const_cast("__signature__"), (getter)Sbk_TypeGet___signature__}, + {const_cast("__doc__"), (getter)Sbk_TypeGet___doc__}, + {nullptr} // Sentinel +}; + static PyType_Slot SbkObjectType_Type_slots[] = { {Py_tp_dealloc, (void *)SbkObjectTypeDealloc}, {Py_tp_setattro, (void *)PyObject_GenericSetAttr}, {Py_tp_base, (void *)&PyType_Type}, {Py_tp_alloc, (void *)PyType_GenericAlloc}, + {Py_tp_getset, (void *)SbkObjectType_Type_getsetlist}, {Py_tp_new, (void *)SbkObjectTypeTpNew}, {Py_tp_free, (void *)PyObject_GC_Del}, {0, 0} diff --git a/sources/shiboken2/libshiboken/signature.cpp b/sources/shiboken2/libshiboken/signature.cpp index c83f90d64..8003f142a 100644 --- a/sources/shiboken2/libshiboken/signature.cpp +++ b/sources/shiboken2/libshiboken/signature.cpp @@ -1180,4 +1180,24 @@ SetError_Argument(PyObject *args, const char *func_name) PyErr_SetObject(err, msg); } +/* + * Support for the metatype SbkObjectType_Type's tp_getset. + * + * This was not necessary for __signature__, because PyType_Type inherited it. + * But the __doc__ attribute existed already by inheritance, and calling + * PyType_Modified() is not supported. So we added the getsets explicitly + * to the metatype. + */ + +PyObject * +Sbk_TypeGet___signature__(PyObject *ob, const char *modifier) +{ + return pyside_tp_get___signature__(ob, modifier); +} + +PyObject *Sbk_TypeGet___doc__(PyObject *ob) +{ + return pyside_tp_get___doc__(ob); +} + } //extern "C" diff --git a/sources/shiboken2/libshiboken/signature.h b/sources/shiboken2/libshiboken/signature.h index 6b477c52e..57fd4047a 100644 --- a/sources/shiboken2/libshiboken/signature.h +++ b/sources/shiboken2/libshiboken/signature.h @@ -48,6 +48,8 @@ extern "C" LIBSHIBOKEN_API int SbkSpecial_Type_Ready(PyObject *, PyTypeObject *, const char *[]); LIBSHIBOKEN_API void FinishSignatureInitialization(PyObject *, const char *[]); LIBSHIBOKEN_API void SetError_Argument(PyObject *, const char *); +LIBSHIBOKEN_API PyObject *Sbk_TypeGet___signature__(PyObject *, const char *); +LIBSHIBOKEN_API PyObject *Sbk_TypeGet___doc__(PyObject *); } // extern "C" -- cgit v1.2.3 From 1eb777f3846685b366207827a9c01a874cda91c8 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Wed, 29 May 2019 09:46:18 +0200 Subject: Signature: Try to recognize unknown modules in errorhandler.py There were unknown modules built with shiboken which mapping.py did not recognize. This is too restrictive, since we can import this module and try to produce something useful. This was rewritten to respect every binary module in sys.modules . Change-Id: I6626c69f002c307bae3eb78a557d1a7309983324 Fixes: PYSIDE-1009 Reviewed-by: Cristian Maureira-Fredes --- .../files.dir/shibokensupport/signature/mapping.py | 94 ++++++++++------------ 1 file changed, 42 insertions(+), 52 deletions(-) (limited to 'sources') diff --git a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py index 306103304..5f92446cf 100644 --- a/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py +++ b/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py @@ -208,25 +208,20 @@ class Reloader(object): This is a singleton class which provides the update function for the shiboken and PySide classes. """ - _uninitialized = "Shiboken minimal sample other smart".split() - _prefixes = [""] - try: - import PySide2 - _uninitialized += PySide2.__all__ + ["testbinding"] - _prefixes += ["PySide2."] - except ImportError: - pass - def __init__(self): self.sys_module_count = 0 - self.uninitialized = self._uninitialized + + @staticmethod + def module_valid(mod): + if getattr(mod, "__file__", None) and not os.path.isdir(mod.__file__): + ending = os.path.splitext(mod.__file__)[-1] + return ending not in (".py", ".pyc", ".pyo", ".pyi") + return False def update(self): """ - update is responsible to import all modules from shiboken and PySide - which are already in sys.modules. - The purpose is to follow all user imports without introducing new - ones. + 'update' imports all binary modules which are already in sys.modules. + The reason is to follow all user imports without introducing new ones. This function is called by pyside_type_init to adapt imports when the number of imported modules has changed. """ @@ -234,37 +229,32 @@ class Reloader(object): return self.sys_module_count = len(sys.modules) g = globals() - for mod_name in self.uninitialized[:]: - for prefix in self._prefixes: - import_name = prefix + mod_name - if import_name in sys.modules: - # check if this is a real module - check_module(sys.modules[import_name]) - # module is real - self.uninitialized.remove(mod_name) - proc_name = "init_" + mod_name - if proc_name in g: - # Do the 'import {import_name}' first. - # 'top' is PySide2 when we do 'import PySide.QtCore' - # or Shiboken if we do 'import Shiboken'. - # Convince yourself that these two lines below have the same - # global effect as "import Shiboken" or "import PySide2.QtCore". - top = __import__(import_name) - g[top.__name__] = top - # Modules are in place, we can update the type_map. - g.update(g[proc_name]()) + # PYSIDE-1009: Try to recognize unknown modules in errorhandler.py + candidates = list(mod_name for mod_name in sys.modules + if self.module_valid(sys.modules[mod_name])) + for mod_name in candidates: + # 'top' is PySide2 when we do 'import PySide.QtCore' + # or Shiboken if we do 'import Shiboken'. + # Convince yourself that these two lines below have the same + # global effect as "import Shiboken" or "import PySide2.QtCore". + top = __import__(mod_name) + g[top.__name__] = top + proc_name = "init_" + mod_name.replace(".", "_") + if proc_name in g: + # Modules are in place, we can update the type_map. + g.update(g.pop(proc_name)()) + def check_module(mod): # During a build, there exist the modules already as directories, # although the '*.so' was not yet created. This causes a problem # in Python 3, because it accepts folders as namespace modules # without enforcing an '__init__.py'. - if not getattr(mod, "__file__", None) or os.path.isdir(mod.__file__): + if not Reloader.module_valid(mod): mod_name = mod.__name__ - raise ImportError("Module '{mod_name}' is at most a namespace!" + raise ImportError("Module '{mod_name}' is not a binary module!" .format(**locals())) - update_mapping = Reloader().update type_map = {} namespace = globals() # our module's __dict__ @@ -274,6 +264,7 @@ type_map.update({ "QVector": typing.List, "QSet": typing.Set, "QPair": Pair, + "QMap": typing.Dict, }) @@ -348,7 +339,7 @@ def init_smart(): return locals() # The PySide Part -def init_QtCore(): +def init_PySide2_QtCore(): from PySide2.QtCore import Qt, QUrl, QDir from PySide2.QtCore import QRect, QSize, QPoint, QLocale, QByteArray from PySide2.QtCore import QMarginsF # 5.9 @@ -401,7 +392,6 @@ def init_QtCore(): "list of QAbstractState": typing.List[PySide2.QtCore.QAbstractState], "list of QAbstractAnimation": typing.List[PySide2.QtCore.QAbstractAnimation], "QVariant()": Invalid(Variant), - "QMap": typing.Dict, "PySide2.QtCore.bool": bool, "QHash": typing.Dict, "PySide2.QtCore.QChar": Char, @@ -495,7 +485,7 @@ def init_QtCore(): return locals() -def init_QtGui(): +def init_PySide2_QtGui(): from PySide2.QtGui import QPageLayout, QPageSize # 5.12 macOS type_map.update({ "QVector< QTextLayout.FormatRange >()": [], # do we need more structure? @@ -525,7 +515,7 @@ def init_QtGui(): return locals() -def init_QtWidgets(): +def init_PySide2_QtWidgets(): from PySide2.QtWidgets import QWidget, QMessageBox, QStyleOption, QStyleHintReturn, QStyleOptionComplex from PySide2.QtWidgets import QGraphicsItem, QStyleOptionGraphicsItem # 5.9 type_map.update({ @@ -557,7 +547,7 @@ def init_QtWidgets(): return locals() -def init_QtSql(): +def init_PySide2_QtSql(): from PySide2.QtSql import QSqlDatabase type_map.update({ "QLatin1String(defaultConnection)": QSqlDatabase.defaultConnection, @@ -566,7 +556,7 @@ def init_QtSql(): return locals() -def init_QtNetwork(): +def init_PySide2_QtNetwork(): type_map.update({ "QMultiMap": MultiMap, "zero(unsigned short)": 0, @@ -576,7 +566,7 @@ def init_QtNetwork(): return locals() -def init_QtXmlPatterns(): +def init_PySide2_QtXmlPatterns(): from PySide2.QtXmlPatterns import QXmlName type_map.update({ "QXmlName.PrefixCode": Missing("PySide2.QtXmlPatterns.QXmlName.PrefixCode"), @@ -585,7 +575,7 @@ def init_QtXmlPatterns(): return locals() -def init_QtMultimedia(): +def init_PySide2_QtMultimedia(): import PySide2.QtMultimediaWidgets # Check if foreign import is valid. See mapping.py in shiboken2. check_module(PySide2.QtMultimediaWidgets) @@ -596,7 +586,7 @@ def init_QtMultimedia(): return locals() -def init_QtOpenGL(): +def init_PySide2_QtOpenGL(): type_map.update({ "GLuint": int, "GLenum": int, @@ -612,7 +602,7 @@ def init_QtOpenGL(): return locals() -def init_QtQml(): +def init_PySide2_QtQml(): type_map.update({ "QJSValueList()": [], "PySide2.QtQml.bool volatile": bool, @@ -624,7 +614,7 @@ def init_QtQml(): return locals() -def init_QtQuick(): +def init_PySide2_QtQuick(): type_map.update({ "PySide2.QtQuick.QSharedPointer": int, "PySide2.QtCore.uint": int, @@ -635,35 +625,35 @@ def init_QtQuick(): return locals() -def init_QtScript(): +def init_PySide2_QtScript(): type_map.update({ "QScriptValueList()": [], }) return locals() -def init_QtTest(): +def init_PySide2_QtTest(): type_map.update({ "PySide2.QtTest.QTouchEventSequence": PySide2.QtTest.QTest.QTouchEventSequence, }) return locals() # from 5.9 -def init_QtWebEngineWidgets(): +def init_PySide2_QtWebEngineWidgets(): type_map.update({ "zero(PySide2.QtWebEngineWidgets.QWebEnginePage.FindFlags)": 0, }) return locals() # from 5.6, MSVC -def init_QtWinExtras(): +def init_PySide2_QtWinExtras(): type_map.update({ "QList< QWinJumpListItem* >()": [], }) return locals() # from 5.12, macOS -def init_QtDataVisualization(): +def init_PySide2_QtDataVisualization(): from PySide2.QtDataVisualization import QtDataVisualization QtDataVisualization.QBarDataRow = typing.List[QtDataVisualization.QBarDataItem] QtDataVisualization.QBarDataArray = typing.List[QtDataVisualization.QBarDataRow] -- cgit v1.2.3 From 4a1d5f1d6cc6325c8e26512f408966821b41c480 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 5 Jun 2019 12:00:45 +0200 Subject: shiboken: Enable specifying names for a parameters of added functions Introduce a way to specify a name for a parameter using '@' delimiters. Fixes: PYSIDE-1017 Change-Id: I3ae505c104a64413ca2bad628d9f9d3e04bb5b88 Reviewed-by: Qt CI Bot Reviewed-by: Cristian Maureira-Fredes --- .../shiboken2/ApiExtractor/abstractmetabuilder.cpp | 6 ++-- .../ApiExtractor/tests/testaddfunction.cpp | 10 +++++-- sources/shiboken2/ApiExtractor/typesystem.cpp | 35 ++++++++++++++++++++-- sources/shiboken2/ApiExtractor/typesystem.h | 11 +++++-- .../doc/typesystem_manipulating_objects.rst | 7 +++++ 5 files changed, 59 insertions(+), 10 deletions(-) (limited to 'sources') diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp index 67489b151..170a8e1d4 100644 --- a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -1615,11 +1615,11 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu metaFunction->setType(translateType(addedFunc->returnType())); - QVector args = addedFunc->arguments(); + const auto &args = addedFunc->arguments(); AbstractMetaArgumentList metaArguments; for (int i = 0; i < args.count(); ++i) { - AddedFunction::TypeInfo& typeInfo = args[i]; + const AddedFunction::TypeInfo& typeInfo = args.at(i).typeInfo; AbstractMetaArgument *metaArg = new AbstractMetaArgument; AbstractMetaType *type = translateType(typeInfo); if (Q_UNLIKELY(!type)) { @@ -1630,6 +1630,8 @@ AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFu return nullptr; } type->decideUsagePattern(); + if (!args.at(i).name.isEmpty()) + metaArg->setName(args.at(i).name); metaArg->setType(type); metaArg->setArgumentIndex(i); metaArg->setDefaultValueExpression(typeInfo.defaultValue); diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp index 8c443527e..c50084b8e 100644 --- a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp +++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp @@ -46,17 +46,21 @@ void TestAddFunction::testParsingFuncNameAndConstness() QCOMPARE(retval.isReference, false); // test with a ugly template as argument and other ugly stuff - const char sig2[] = " _fu__nc_ ( type1, const type2, const Abc * > * *, const type3* const ) const "; + const char sig2[] = " _fu__nc_ ( type1, const type2, const Abc * > * *@my_name@, const type3* const ) const "; AddedFunction f2(QLatin1String(sig2), QLatin1String("const Abc * > * *")); QCOMPARE(f2.name(), QLatin1String("_fu__nc_")); - QVector< AddedFunction::TypeInfo > args = f2.arguments(); + const auto &args = f2.arguments(); QCOMPARE(args.count(), 4); retval = f2.returnType(); QCOMPARE(retval.name, QLatin1String("Abc * >")); QCOMPARE(retval.indirections, 2); QCOMPARE(retval.isConstant, true); QCOMPARE(retval.isReference, false); - retval = args[2]; + retval = args.at(2).typeInfo; + QVERIFY(args.at(0).name.isEmpty()); + QVERIFY(args.at(1).name.isEmpty()); + QCOMPARE(args.at(2).name, QLatin1String("my_name")); + QVERIFY(args.at(3).name.isEmpty()); QCOMPARE(retval.name, QLatin1String("Abc * >")); QCOMPARE(retval.indirections, 2); QCOMPARE(retval.isConstant, true); diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp index 434134be9..344313e87 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.cpp +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -3279,7 +3279,9 @@ QString FunctionModification::toString() const return str; } -static AddedFunction::TypeInfo parseType(const QString& signature, int startPos = 0, int* endPos = 0) +static AddedFunction::TypeInfo parseType(const QString& signature, + int startPos = 0, int *endPos = nullptr, + QString *argumentName = nullptr) { AddedFunction::TypeInfo result; static const QRegularExpression regex(QLatin1String("\\w")); @@ -3330,6 +3332,19 @@ static AddedFunction::TypeInfo parseType(const QString& signature, int startPos paramString.remove(0, sizeof("const")/sizeof(char)); paramString = paramString.trimmed(); } + + // Extract argument name from "T* @foo@" + const int nameStartPos = paramString.indexOf(QLatin1Char('@')); + if (nameStartPos != -1) { + const int nameEndPos = paramString.indexOf(QLatin1Char('@'), nameStartPos + 1); + if (nameEndPos > nameStartPos) { + if (argumentName) + *argumentName = paramString.mid(nameStartPos + 1, nameEndPos - nameStartPos - 1); + paramString.remove(nameStartPos, nameEndPos - nameStartPos + 1); + paramString = paramString.trimmed(); + } + } + // check reference if (paramString.endsWith(QLatin1Char('&'))) { result.isReference = true; @@ -3364,9 +3379,10 @@ AddedFunction::AddedFunction(QString signature, const QString &returnType) : m_name = signature.left(endPos).trimmed(); int signatureLength = signature.length(); while (endPos < signatureLength) { - TypeInfo arg = parseType(signature, endPos, &endPos); + QString argumentName; + TypeInfo arg = parseType(signature, endPos, &endPos, &argumentName); if (!arg.name.isEmpty()) - m_arguments.append(arg); + m_arguments.append({argumentName, arg}); // end of parameters... if (signature[endPos] == QLatin1Char(')')) break; @@ -3512,6 +3528,19 @@ QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti) return d; } +QDebug operator<<(QDebug d, const AddedFunction::Argument &a) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "Argument("; + d << a.typeInfo; + if (!a.name.isEmpty()) + d << ' ' << a.name; + d << ')'; + return d; +} + QDebug operator<<(QDebug d, const AddedFunction &af) { QDebugStateSaver saver(d); diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h index 2e4578a1d..82a698107 100644 --- a/sources/shiboken2/ApiExtractor/typesystem.h +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -424,6 +424,12 @@ struct AddedFunction bool isReference = false; }; + struct Argument + { + QString name; + TypeInfo typeInfo; + }; + /// Creates a new AddedFunction with a signature and a return type. explicit AddedFunction(QString signature, const QString &returnType); AddedFunction() = default; @@ -453,7 +459,7 @@ struct AddedFunction } /// Returns a list of argument type infos. - QVector arguments() const + const QVector &arguments() const { return m_arguments; } @@ -480,7 +486,7 @@ struct AddedFunction private: QString m_name; - QVector m_arguments; + QVector m_arguments; TypeInfo m_returnType; Access m_access = Protected; bool m_isConst = false; @@ -489,6 +495,7 @@ private: #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti); +QDebug operator<<(QDebug d, const AddedFunction::Argument &a); QDebug operator<<(QDebug d, const AddedFunction &af); #endif diff --git a/sources/shiboken2/doc/typesystem_manipulating_objects.rst b/sources/shiboken2/doc/typesystem_manipulating_objects.rst index 12b866ad7..c04a4fa27 100644 --- a/sources/shiboken2/doc/typesystem_manipulating_objects.rst +++ b/sources/shiboken2/doc/typesystem_manipulating_objects.rst @@ -157,6 +157,13 @@ add-function The ``since`` attribute specify the API version when this function was added. + Within the signature, names for the function parameters can be specified by + enclosing them within the delimiter *@*: + + .. code-block:: c++ + + void foo(int @parameter1@,float) + .. _conversion-rule-on-types: conversion-rule -- cgit v1.2.3 From d21b58ef69559f4a0412f5129175b31e4450d55b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 13 Jun 2019 14:55:19 +0200 Subject: shiboken: Fix handling shared pointers passed by const-ref, take 2 With fd126b28e1d9b02ea16c813bc392461bdb05bd1d, broken wrapper code would still be generated for "const_QSharedPointer_QSize___&" depending on whether the const-ref or plain value type was encountered first when parsing. Fix the problem by stripping the qualifiers from the metatype added to GeneratorPrivate::m_instantiatedSmartPointers partially reverting fd126b28e1d9b02ea16c813bc392461bdb05bd1d. Change-Id: Ie6691e045b7d65baa3a0bc72dd8637f09eeaf111 Fixes: PYSIDE-1016 Reviewed-by: Cristian Maureira-Fredes --- sources/shiboken2/generator/generator.cpp | 8 +++++++- sources/shiboken2/generator/shiboken2/headergenerator.cpp | 6 ++---- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'sources') diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp index fe03d3489..46ad90724 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -244,6 +244,13 @@ void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType // Is smart pointer. if (!m_d->instantiatedSmartPointerNames.contains(typeName)) { m_d->instantiatedSmartPointerNames.append(typeName); + if (type->isConstant() || type->referenceType() != NoReference) { + // Strip a "const QSharedPtr &" or similar to "QSharedPtr" (PYSIDE-1016) + auto fixedType = type->copy(); + fixedType->setReferenceType(NoReference); + fixedType->setConstant(false); + type = fixedType; + } m_d->instantiatedSmartPointers.append(type); } } @@ -912,7 +919,6 @@ QString getClassTargetFullName(const AbstractMetaType *metaType, bool includePac QString getFilteredCppSignatureString(QString signature) { - TypeInfo::stripQualifiers(&signature); // for const refs to smart pointers signature.replace(QLatin1String("::"), QLatin1String("_")); signature.replace(QLatin1Char('<'), QLatin1Char('_')); signature.replace(QLatin1Char('>'), QLatin1Char('_')); diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp index 17ebbcde9..a55539d7c 100644 --- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp @@ -593,10 +593,8 @@ void HeaderGenerator::writeSbkTypeFunction(QTextStream& s, const AbstractMetaCla void HeaderGenerator::writeSbkTypeFunction(QTextStream &s, const AbstractMetaType *metaType) { - QString signature = metaType->cppSignature(); - TypeInfo::stripQualifiers(&signature); // for const refs to smart pointers - s << "template<> inline PyTypeObject *SbkType< ::" << signature << " >() " - << "{ return reinterpret_cast(" << cpythonTypeNameExt(metaType) << "); }\n"; + s << "template<> inline PyTypeObject* SbkType< ::" << metaType->cppSignature() << " >() " + << "{ return reinterpret_cast(" << cpythonTypeNameExt(metaType) << "); }\n"; } void HeaderGenerator::writeInheritedOverloads(QTextStream& s) -- cgit v1.2.3 From b1402395381198539d23e65a6595a156ad395b24 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 13 Jun 2019 15:51:23 +0200 Subject: Revert "shiboken: Disambiguate indexes of smart pointer types" This is not the proper fix for the issue. The index of the declaring module needs to be used for this to work. This reverts commit d2d0e397309a1b18eaff9ddee0940007f0e1c4bf. Task-number: PYSIDE-1024 Change-Id: Idc0e859ebda1626b5e841aa96be54317a5f3d0d0 Reviewed-by: Cristian Maureira-Fredes --- sources/shiboken2/generator/shiboken2/shibokengenerator.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sources') diff --git a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp index 5d599fe95..2b3b20c75 100644 --- a/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/shibokengenerator.cpp @@ -2681,11 +2681,8 @@ QString ShibokenGenerator::getTypeIndexVariableName(const TypeEntry* type) QString ShibokenGenerator::getTypeIndexVariableName(const AbstractMetaType* type) { QString result = QLatin1String("SBK"); - const auto *typeEntry = type->typeEntry(); - if (typeEntry->isContainer() - || typeEntry->isSmartPointer()) { // PYSIDE-1024 + if (type->typeEntry()->isContainer()) result += QLatin1Char('_') + moduleName().toUpper(); - } result += processInstantiationsVariableName(type); appendIndexSuffix(&result); return result; -- cgit v1.2.3 From 80a6f91c553eaf9ed4d7d002a5abb442693e8e08 Mon Sep 17 00:00:00 2001 From: Christian Tismer Date: Thu, 23 May 2019 19:35:51 +0200 Subject: Support the qApp macro in "scriptable application" Renamed from "Fix scriptable application to support the qApp macro" because qApp was improved instead of scriptable application. The qApp macro needed some extra effort to support the qApp "macro" which is only defined in the Python wrappers. I took some generated code, created a QApplication instance in Python and used then reduced generated code to get at the object and adjust the refcount. This solution was then rejected, because I can do better, and in fact, scriptable application now has a correct qApp macro too, without any change to scriptable application. The central idea was to look into the module init function at import time and to see if a Q*Application already exists. I was not aware of that import. Many thanks for the rejection! :-) Update.. -------- After many attempts to make the qApp variable correctly behave like always, I recognized that pre-existing Q*Application instances have no wrappers or constructors at all! With that, it is not possible to create a sophisticated qApp macro as a singleton variable in the desired way. Fortunately, this is also not necessary, because a C++ Q*Application cannot be deleted from Python, and there is no point in supporting more that a simple variable. So in case of a pre-existing instance, the qApp variable now gets redirected to that instance. A small test was added to application_test.py that is triggered by an import. A weird effect when "qApp" was typed interactively before calling "QApplication()" was fixed, too. Change-Id: Ic69dd6a21c964838a90f63e316d299b62a54d612 Fixes: PYSIDE-571 Reviewed-by: Cristian Maureira-Fredes --- sources/pyside2/PySide2/glue/qtcore.cpp | 9 +++-- .../pyside2/tests/QtWidgets/application_test.py | 8 ++++- .../shiboken2/generator/shiboken2/cppgenerator.cpp | 2 +- sources/shiboken2/libshiboken/qapp_macro.cpp | 41 ++++++++++++++++++---- sources/shiboken2/libshiboken/qapp_macro.h | 2 +- 5 files changed, 47 insertions(+), 15 deletions(-) (limited to 'sources') diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index f30607f6b..9db4e2e82 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -1340,18 +1340,17 @@ if (!PyTuple_SetItem(empty, 0, PyList_New(0))) { // @snippet qcoreapplication-2 // @snippet qcoreapplication-instance -QCoreApplication *app = QCoreApplication::instance(); PyObject *pyApp = Py_None; -if (app) { +if (qApp) { pyApp = reinterpret_cast( - Shiboken::BindingManager::instance().retrieveWrapper(app)); + Shiboken::BindingManager::instance().retrieveWrapper(qApp)); if (!pyApp) - pyApp = %CONVERTTOPYTHON[QCoreApplication*](app); + pyApp = %CONVERTTOPYTHON[QCoreApplication*](qApp); // this will keep app live after python exit (extra ref) } // PYSIDE-571: make sure that we return the singleton "None" if (pyApp == Py_None) - Py_DECREF(MakeSingletonQAppWrapper(0)); // here qApp and instance() diverge + Py_DECREF(MakeSingletonQAppWrapper(nullptr)); // here qApp and instance() diverge %PYARG_0 = pyApp; Py_XINCREF(%PYARG_0); // @snippet qcoreapplication-instance diff --git a/sources/pyside2/tests/QtWidgets/application_test.py b/sources/pyside2/tests/QtWidgets/application_test.py index bd0f94125..0b8f73cd6 100644 --- a/sources/pyside2/tests/QtWidgets/application_test.py +++ b/sources/pyside2/tests/QtWidgets/application_test.py @@ -31,19 +31,25 @@ import unittest from testbinding import TestObject from PySide2.QtWidgets import QApplication +from PySide2 import __all__ as all class QApplicationInstance(unittest.TestCase): def appDestroyed(self): - sefl.assertTrue(False) + self.assertTrue(False) def testInstanceObject(self): + self.assertEqual(type(qApp), type(None)) TestObject.createApp() app1 = QApplication.instance() app2 = QApplication.instance() app1.setObjectName("MyApp") self.assertEqual(app1, app2) self.assertEqual(app2.objectName(), app1.objectName()) + if len(all) > 3: + # an import triggers qApp initialization + __import__("PySide2." + all[-1]) + self.assertEqual(app1, qApp) app1.destroyed.connect(self.appDestroyed) if __name__ == '__main__': diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index 8ee0a9cf2..d1da3a4ba 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -5806,7 +5806,7 @@ bool CppGenerator::finishGeneration() if (usePySideExtensions()) { // initialize the qApp module. - s << INDENT << "NotifyModuleForQApp(module);" << endl; + s << INDENT << "NotifyModuleForQApp(module, qApp);" << endl; } s << endl; s << "SBK_MODULE_INIT_FUNCTION_END" << endl; diff --git a/sources/shiboken2/libshiboken/qapp_macro.cpp b/sources/shiboken2/libshiboken/qapp_macro.cpp index 19e985b20..ea9cf0c86 100644 --- a/sources/shiboken2/libshiboken/qapp_macro.cpp +++ b/sources/shiboken2/libshiboken/qapp_macro.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "basewrapper.h" +#include "autodecref.h" extern "C" { @@ -93,13 +94,14 @@ static int qApp_var_ref = 0; static int qApp_content_ref = 0; static int -reset_qApp_var() +reset_qApp_var(void) { PyObject **mod_ptr; - for (mod_ptr = qApp_moduledicts; *mod_ptr != NULL; mod_ptr++) { + for (mod_ptr = qApp_moduledicts; *mod_ptr != nullptr; mod_ptr++) { // We respect whatever the user may have set. - if (PyDict_GetItem(*mod_ptr, qApp_var) == NULL) { + PyObject *existing = PyDict_GetItem(*mod_ptr, qApp_var); + if (existing == nullptr || Py_TYPE(existing) == Py_NONE_TYPE) { if (PyDict_SetItem(*mod_ptr, qApp_var, qApp_content) < 0) return -1; } @@ -135,8 +137,13 @@ MakeSingletonQAppWrapper(PyTypeObject *type) if (Py_REFCNT(qApp_content) > qApp_content_ref) qApp_content_ref = Py_REFCNT(qApp_content); - if (Py_TYPE(qApp_content) != Py_NONE_TYPE) + if (Py_TYPE(qApp_content) != Py_NONE_TYPE) { + // Remove the "_" variable which might hold a reference to qApp. + Shiboken::AutoDecRef pymain(PyImport_ImportModule("__main__")); + if (pymain.object() && PyObject_HasAttrString(pymain.object(), "_")) + PyObject_DelAttrString(pymain.object(), "_"); Py_REFCNT(qApp_var) = 1; // fuse is armed... + } if (type == Py_NONE_TYPE) { // Debug mode showed that we need to do more than just remove the // reference. To keep everything in the right order, it is easiest @@ -149,8 +156,8 @@ MakeSingletonQAppWrapper(PyTypeObject *type) Py_TYPE(qApp_content) = Py_NONE_TYPE; Py_REFCNT(qApp_var) = qApp_var_ref; Py_REFCNT(qApp_content) = Py_REFCNT(Py_None); - if (__moduleShutdown != NULL) - Py_DECREF(PyObject_CallFunction(__moduleShutdown, (char *)"()")); + if (__moduleShutdown != nullptr) + Py_XDECREF(PyObject_CallFunction(__moduleShutdown, const_cast("()"))); } else (void)PyObject_INIT(qApp_content, type); @@ -216,9 +223,29 @@ setup_qApp_var(PyObject *module) } void -NotifyModuleForQApp(PyObject *module) +NotifyModuleForQApp(PyObject *module, void *qApp) { setup_qApp_var(module); + /* + * PYSIDE-571: Check if an QApplication instance exists before the import. + * This happens in scriptableapplication and application_test.py . + * + * Crucial Observation + * =================== + * + * A Q*Application object from C++ does not have a wrapper or constructor + * like instances created by Python. It makes no sense to support + * deletion or special features like qApp resurrection. + * + * Therefore, the implementation is very simple and just redirects the + * qApp_contents variable and assigns the instance, instead of vice-versa. + */ + if (qApp != nullptr) { + Shiboken::AutoDecRef pycore(PyImport_ImportModule("PySide2.QtCore")); + Shiboken::AutoDecRef coreapp(PyObject_GetAttrString(pycore, "QCoreApplication")); + qApp_content = PyObject_CallMethod(coreapp, "instance", ""); + reset_qApp_var(); + } } diff --git a/sources/shiboken2/libshiboken/qapp_macro.h b/sources/shiboken2/libshiboken/qapp_macro.h index ded892383..be45241de 100644 --- a/sources/shiboken2/libshiboken/qapp_macro.h +++ b/sources/shiboken2/libshiboken/qapp_macro.h @@ -46,7 +46,7 @@ extern "C" { LIBSHIBOKEN_API PyObject *MakeSingletonQAppWrapper(PyTypeObject *type); -LIBSHIBOKEN_API void NotifyModuleForQApp(PyObject *module); +LIBSHIBOKEN_API void NotifyModuleForQApp(PyObject *module, void *qApp); } // extern "C" -- cgit v1.2.3 From 6e77dec18651a023b8447ed7ce64c2a1db6e2462 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 13 Jun 2019 15:55:24 +0200 Subject: shiboken: Generate code for smart pointers only within declaring package Check on the type entry whether code needs to be generated in the current package. Fixes: PYSIDE-1024 Change-Id: I82132b077ac6192b96d979cb5596d0e6fecbc76b Reviewed-by: Cristian Maureira-Fredes --- sources/shiboken2/generator/generator.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sources') diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp index 46ad90724..49064a6a5 100644 --- a/sources/shiboken2/generator/generator.cpp +++ b/sources/shiboken2/generator/generator.cpp @@ -219,9 +219,12 @@ void Generator::addInstantiatedContainersAndSmartPointers(const AbstractMetaType const AbstractMetaTypeList &instantiations = type->instantiations(); for (const AbstractMetaType* t : instantiations) addInstantiatedContainersAndSmartPointers(t, context); - if (!type->typeEntry()->isContainer() && !type->typeEntry()->isSmartPointer()) + const auto typeEntry = type->typeEntry(); + const bool isContainer = typeEntry->isContainer(); + if (!isContainer + && !(typeEntry->isSmartPointer() && typeEntry->generateCode())) { return; - bool isContainer = type->typeEntry()->isContainer(); + } if (type->hasTemplateChildren()) { QString piece = isContainer ? QStringLiteral("container") : QStringLiteral("smart pointer"); QString warning = -- cgit v1.2.3 From 7dba09d7c4007e96fb0a39bf6f6e740cd207324a Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 17 Jun 2019 10:09:40 +0200 Subject: Fix type name for lookup of QFlags<> converters For enum/flags registration, the converters were registered under invalid names like: Shiboken::Conversions::registerConverterName(converter, "QFlags"); Shiboken::Conversions::registerConverterName(converter, "QFlags"); In addition, QFlags<> is not used for type names in Python. Use the flags name as specified in the typesystem instead: Shiboken::Conversions::registerConverterName(converter, "QUrl::ComponentFormattingOptions"); Shiboken::Conversions::registerConverterName(converter, "ComponentFormattingOptions"); Change-Id: I79525643850bf4296516dfb9576f75b51adf6414 Fixes: PYSIDE-1029 Reviewed-by: Christian Tismer --- .../shiboken2/generator/shiboken2/cppgenerator.cpp | 31 ++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'sources') diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp index d1da3a4ba..c033b8a21 100644 --- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp +++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp @@ -3686,14 +3686,29 @@ void CppGenerator::writeEnumConverterInitialization(QTextStream& s, const TypeEn } s << INDENT << "Shiboken::Enum::setTypeConverter(" << enumPythonType << ", converter);" << endl; - QStringList cppSignature = enumType->qualifiedCppName().split(QLatin1String("::"), QString::SkipEmptyParts); - while (!cppSignature.isEmpty()) { - QString signature = cppSignature.join(QLatin1String("::")); - s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \""; - if (flags) - s << "QFlags<"; - s << signature << "\");" << endl; - cppSignature.removeFirst(); + + QString signature = enumType->qualifiedCppName(); + // Replace "QFlags" by "Class::Options" + if (flags && signature.startsWith(QLatin1String("QFlags<")) && signature.endsWith(QLatin1Char('>'))) { + signature.chop(1); + signature.remove(0, 7); + const int lastQualifierPos = signature.lastIndexOf(QLatin1String("::")); + if (lastQualifierPos != -1) { + signature.replace(lastQualifierPos + 2, signature.size() - lastQualifierPos - 2, + flags->flagsName()); + } else { + signature = flags->flagsName(); + } + } + + while (true) { + s << INDENT << "Shiboken::Conversions::registerConverterName(converter, \"" + << signature << "\");\n"; + const int qualifierPos = signature.indexOf(QLatin1String("::")); + if (qualifierPos != -1) + signature.remove(0, qualifierPos + 2); + else + break; } } s << INDENT << '}' << endl; -- cgit v1.2.3