diff options
author | Christian Tismer <tismer@stackless.com> | 2021-01-04 19:10:52 +0100 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2021-01-11 15:48:42 +0000 |
commit | db9e8e575538c627f9808592e895a9c544d16c4e (patch) | |
tree | 2babb8174e5c0a4ca8ffa77a6d15ced161035557 | |
parent | a2c4cc01db8d09161349e0ac8489063c2d1383e7 (diff) |
allow to use shiboken.delete() to delete Q*Application
This function should initially not allow deleting Q*Application
with a shiboken.delete() function, but unfortunately some
competitor can do that, so we will as well.
Deletion of qApp needs knowledge about qApp.
We add a hook function that calls the pyside function
`destroyQCoreApplication`.
A special problem was testing interactively.
See the error description for the days long journey :)
Change-Id: I34862425c2cb2cc80d6cafc22d25a867f96f3e0a
Fixes: PYSIDE-1470
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
(cherry picked from commit 98aba46414b666c27df3904d2b4313f0a16e05dc)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r-- | sources/pyside6/libpyside/pyside.cpp | 3 | ||||
-rw-r--r-- | sources/pyside6/tests/pysidetest/qapp_like_a_macro_test.py | 5 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/basewrapper.cpp | 39 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/basewrapper.h | 3 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/basewrapper_p.h | 3 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/sbkstaticstrings.cpp | 1 | ||||
-rw-r--r-- | sources/shiboken6/libshiboken/sbkstaticstrings.h | 1 |
7 files changed, 46 insertions, 9 deletions
diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp index 75b3eb16f..22230703e 100644 --- a/sources/pyside6/libpyside/pyside.cpp +++ b/sources/pyside6/libpyside/pyside.cpp @@ -308,6 +308,9 @@ void initQApp() */ if (!qApp) Py_DECREF(MakeQAppWrapper(nullptr)); + + // PYSIDE-1470: Register a function to destroy an application from shiboken. + setDestroyQApplication(destroyQCoreApplication); } PyObject *getMetaDataFromQObject(QObject *cppSelf, PyObject *self, PyObject *name) diff --git a/sources/pyside6/tests/pysidetest/qapp_like_a_macro_test.py b/sources/pyside6/tests/pysidetest/qapp_like_a_macro_test.py index 2a796cea8..2233b1b33 100644 --- a/sources/pyside6/tests/pysidetest/qapp_like_a_macro_test.py +++ b/sources/pyside6/tests/pysidetest/qapp_like_a_macro_test.py @@ -59,10 +59,11 @@ class qAppMacroTest(unittest.TestCase): classes = (QtCore.QCoreApplication, QtGui.QGuiApplication, QtWidgets.QApplication) + fil = sys.stderr for klass in classes: - print("created", klass([])) + print("CREATED", klass([]), file=fil); fil.flush() qApp.shutdown() - print("deleted qApp", qApp) + print("DELETED qApp", qApp, file=fil); fil.flush() # creating without deletion raises: QtCore.QCoreApplication([]) with self.assertRaises(RuntimeError): diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp index 62e2df2cf..7f927523a 100644 --- a/sources/shiboken6/libshiboken/basewrapper.cpp +++ b/sources/shiboken6/libshiboken/basewrapper.cpp @@ -95,6 +95,13 @@ static void SbkObjectTypeDealloc(PyObject *pyObj); static PyObject *SbkObjectTypeTpNew(PyTypeObject *metatype, PyObject *args, PyObject *kwds); static SelectableFeatureHook SelectFeatureSet = nullptr; +static DestroyQAppHook DestroyQApplication = nullptr; + +// PYSIDE-1470: Provide a hook to kill an Application from Shiboken. +void setDestroyQApplication(DestroyQAppHook func) +{ + DestroyQApplication = func; +} static PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context); // forward @@ -457,6 +464,12 @@ PyObject *MakeQAppWrapper(PyTypeObject *type) // object already has a reference from PyObject_GC_New. But this is // exactly the needed reference that keeps qApp alive from alone! Py_INCREF(qApp_curr); + // PYSIDE-1470: As a side effect, the interactive "_" variable tends to + // create reference cycles. It was found when using gc.collect(). But using + // PyGC_collect() inside the C code had no effect in the interactive shell. + // The cycle exists only in the eval loop of the interpreter! + if (PyDict_GetItem(builtins, Shiboken::PyName::underscore())) + PyDict_SetItem(builtins, Shiboken::PyName::underscore(), Py_None); return qApp_curr; } @@ -673,7 +686,12 @@ PyObject *SbkObjectTpNew(PyTypeObject *subtype, PyObject *, PyObject *) PyObject *SbkQAppTpNew(PyTypeObject *subtype, PyObject *, PyObject *) { auto self = reinterpret_cast<SbkObject *>(MakeQAppWrapper(subtype)); - return self == nullptr ? nullptr : _setupNew(self, subtype); + if (self == nullptr) + return nullptr; + auto ret = _setupNew(self, subtype); + auto priv = self->d; + priv->isQAppSingleton = 1; + return ret; } PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *) @@ -1154,6 +1172,12 @@ bool wasCreatedByPython(SbkObject *pyObj) void callCppDestructors(SbkObject *pyObj) { + auto priv = pyObj->d; + if (priv->isQAppSingleton && DestroyQApplication) { + // PYSIDE-1470: Allow to destroy the application from Shiboken. + DestroyQApplication(); + return; + } PyTypeObject *type = Py_TYPE(pyObj); SbkObjectTypePrivate *sotp = PepType_SOTP(type); if (sotp->is_multicpp) { @@ -1166,18 +1190,19 @@ void callCppDestructors(SbkObject *pyObj) sotp->cpp_dtor(pyObj->d->cptr[0]); } + if (priv->validCppObject && priv->containsCppWrapper) { + BindingManager::instance().releaseWrapper(pyObj); + } + /* invalidate needs to be called before deleting pointer array because it needs to delete entries for them from the BindingManager hash table; also release wrapper explicitly if object contains C++ wrapper because invalidate doesn't */ invalidate(pyObj); - if (pyObj->d->validCppObject && pyObj->d->containsCppWrapper) { - BindingManager::instance().releaseWrapper(pyObj); - } - delete[] pyObj->d->cptr; - pyObj->d->cptr = nullptr; - pyObj->d->validCppObject = false; + delete[] priv->cptr; + priv->cptr = nullptr; + priv->validCppObject = false; } bool hasOwnership(SbkObject *pyObj) diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h index 364f6c5cb..2f0c22e9f 100644 --- a/sources/shiboken6/libshiboken/basewrapper.h +++ b/sources/shiboken6/libshiboken/basewrapper.h @@ -106,6 +106,9 @@ LIBSHIBOKEN_API void SbkObjectType_SetReserved(PyTypeObject *type, int value); LIBSHIBOKEN_API const char **SbkObjectType_GetPropertyStrings(PyTypeObject *type); LIBSHIBOKEN_API void SbkObjectType_SetPropertyStrings(PyTypeObject *type, const char **strings); +/// PYSIDE-1470: Set the function to kill a Q*Application. +typedef void(*DestroyQAppHook)(); +LIBSHIBOKEN_API void setDestroyQApplication(DestroyQAppHook func); extern LIBSHIBOKEN_API PyTypeObject *SbkObjectType_TypeF(void); extern LIBSHIBOKEN_API SbkObjectType *SbkObject_TypeF(void); diff --git a/sources/shiboken6/libshiboken/basewrapper_p.h b/sources/shiboken6/libshiboken/basewrapper_p.h index 64f7941b7..60fba13c5 100644 --- a/sources/shiboken6/libshiboken/basewrapper_p.h +++ b/sources/shiboken6/libshiboken/basewrapper_p.h @@ -97,6 +97,9 @@ struct SbkObjectPrivate unsigned int validCppObject : 1; /// Marked as true when the object constructor was called unsigned int cppObjectCreated : 1; + /// PYSIDE-1470: Marked as true if this is the Q*Application singleton. + /// This bit allows app deletion from shiboken?.delete() . + unsigned int isQAppSingleton : 1; /// Information about the object parents and children, may be null. Shiboken::ParentInfo *parentInfo; /// Manage reference count of objects that are referred to but not owned from. diff --git a/sources/shiboken6/libshiboken/sbkstaticstrings.cpp b/sources/shiboken6/libshiboken/sbkstaticstrings.cpp index 35fc2a410..fd34c0eeb 100644 --- a/sources/shiboken6/libshiboken/sbkstaticstrings.cpp +++ b/sources/shiboken6/libshiboken/sbkstaticstrings.cpp @@ -61,6 +61,7 @@ STATIC_STRING_IMPL(name, "name") STATIC_STRING_IMPL(qApp, "qApp") STATIC_STRING_IMPL(result, "result") STATIC_STRING_IMPL(select_id, "select_id") +STATIC_STRING_IMPL(underscore, "_") STATIC_STRING_IMPL(value, "value") STATIC_STRING_IMPL(values, "values") diff --git a/sources/shiboken6/libshiboken/sbkstaticstrings.h b/sources/shiboken6/libshiboken/sbkstaticstrings.h index d835d286c..4aaef814f 100644 --- a/sources/shiboken6/libshiboken/sbkstaticstrings.h +++ b/sources/shiboken6/libshiboken/sbkstaticstrings.h @@ -59,6 +59,7 @@ LIBSHIBOKEN_API PyObject *multi(); LIBSHIBOKEN_API PyObject *name(); LIBSHIBOKEN_API PyObject *result(); LIBSHIBOKEN_API PyObject *select_id(); +LIBSHIBOKEN_API PyObject *underscore(); LIBSHIBOKEN_API PyObject *value(); LIBSHIBOKEN_API PyObject *values(); } // namespace PyName |