[PyQt] Conflict between setuptools & requirements in official PyQt5 docs

Kovid Goyal kovid at kovidgoyal.net
Thu Feb 11 02:34:21 GMT 2016

On Wed, Feb 10, 2016 at 03:42:53PM +0000, Phil Thompson wrote:
>     if __name__ = '__main__':
>         app = QApplication([])
>         gui = QWidget()
>         gui.show()
>         app.exec()
> ...there shouldn't be a problem with crashes on exit. If anybody has an example where they think this is not the case then I'd like to know.

The very first PyQt5 crashing on exit example I posted over a year ago, still crashes about 1
in 20 times, but only on Linux, following that exact pattern.

Details of my system:
Kernel 4.4.1 x64
PyQT 5.5.1
Qt 5.5.1
sip 4.16.9

Unfortunately, the crash involves stack corruption, so back traces are
fairly useless, and I cannot get it to happen when running under a

This crash also happens with about the same frequency in a real world
application, which is how I first noticed it. Unfortunately, in that
case there is no simple fix since there are complex reference
relationships between top level widgets, the application object and so

For a real world example that crashes reliably, on every exit, see this
QWebEngine based application:
Changing this line https://github.com/kovidgoyal/vise/blob/master/vise/main.py#L223
to True causes it to crash on exit on every invocation. All that line
does is enable remote debugging in QWebEngine, no other python level
changes are involved.

This is again on linux, I have not tried it on other platforms.

You can run the application by (needs PyQt, libsodium installed):

git clone https://github.com/kovidgoyal/vise.git
python3 vise

> However it is not always possible to follow that pattern - setuptools requires a function entry point. When that function (ie. "scope") returns then the local objects can be garbage collected in a random order. Because the interpreter is still running, the dtors are still invoked.

My point above was that running code in module scope is exactly
equivalent to saving the application object and global widgets in module
global variables, therefore, there is no need to recommend running code
at module level, which does not work with setuptools as you point out. 

Also, it may be useful to allow the user to turn on the sip disable
destructors behavior via an API, that way the user can instead do:

def main():
  app = ...

No need for module level references.

> PyQt5 tries to mitigate this to a certain extent. When a QApplication is garbage collected it first makes sure that any top-level widgets that still exist are owned by C++. This effectively disables the dtors of those widgets. However it does mean that widgets may still outlive the C++ QApplication instance - and maybe Qt doesn't like that.
> The suggestion above (ie. the global reference to the QApplication object) has the effect of guaranteeing that the QApplication instance will outlive any objects that are garbage collected when main() returns. In fact the QApplication dtor will never be invoked as the object will only be garbage collected when the interpreter exits.
> This pattern, therefore, should also avoid any crashes on exit. Again, if anybody has a counter example then I'd like to know.
> I am considering changing the behaviour when the QApplication object gets garbage collected. Instead of transferring ownership of any top-level widgets it would instead explicitly invoke their dtors. This would guarantee the QApplication outlives any widgets (as the global reference trick does) but it would not be able to make the same guarantee regarding any other objects that might be referenced at the global level. However I think it would be an improvement over the current behaviour.

Seems rather hacky to me, but, if it works around the crashes, I dont
see the harm, since widgets cannot exist without an application in any



Dr. Kovid Goyal 

More information about the PyQt mailing list