Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyQt5 app exits on error where PyQt4 app would not

I have been developing a scientific application using PyQt4 for a couple of weeks, and decided to switch over to PyQt5. Aside from a few things to iron out one thing is puzzling me, and I'm not sure if its intended behavior or not.

When Using PyQt4: if I had a python error (AttributeError, FileNotFoundError or whatever) the error message would print out to the python console, but I could continue using the PyQt4 gui application

When Using PyQt5, when I have a python error, the entire app closes on me. Is this a setting, or is this intended behavior? This is potentially disastrous as before if there was a bug, I could save the data I had acquired, but now the application will just close without warning.

Here is an example that demonstrates the behavior. This script opens a widget with a button that activates a file dialog. If a valid file is selected, the code will print the filepointer object to the command line. If no file is selected because the user hits cancel, then that case is not handled and python tries to open a file with path ''. In this both PyQt4 and PyQt5 versions throw the same python error:

FileNotFoundError: [Errno 2] No such file or directory: ''

However, the PyQt4 version will leave the widget open and the user can continue, whereas the PyQt5 version closes, with exit code of 1.

Here is the example code, executed by: "python script.py"

import sys
# from PyQt4 import QtGui as qt
# from PyQt4.QtCore import PYQT_VERSION_STR
from PyQt5 import QtWidgets as qt
from PyQt5.QtCore import PYQT_VERSION_STR

def open_a_file():
    fname = qt.QFileDialog.getOpenFileName()
    if PYQT_VERSION_STR[0] == '4':
        f = open(fname, 'r')
        print(f)
    else:
        f = open(fname[0], 'r')
        print(f)
    f.close()

if __name__ == '__main__':
    app = qt.QApplication(sys.argv)

    w = qt.QWidget()
    w.resize(250, 150)
    w.move(300, 300)
    w.setWindowTitle('PyQt 4 v 5')
    btn = qt.QPushButton("Open a file", w)
    btn.clicked.connect(open_a_file)
    w.show()

    sys.exit(app.exec_())

Can I use PyQt5, but have it not crash the way that the PyQt4 version does?

Here is my current system information system information:
Windows 7 64-bit
Anaconda, Python 3.5
PyQt4 --> from conda sources
PyQt5 --> using:

conda install --channel https://conda.anaconda.org/m-labs qt5
conda install --channel https://conda.anaconda.org/m-labs pyqt5

both PyQt4 and PyQt5 are installed side by side

like image 995
Vince W. Avatar asked Jun 24 '16 18:06

Vince W.


People also ask

Is PyQt5 better than PyQt6?

As we've discovered, there are no major differences between PyQt5 and PyQt6. The changes that are there can be easily worked around. If you are new to Python GUI programming with Qt you may find it easier to start with PyQt5 still, but for any new project I'd suggest starting with PyQt6.

Is PySide and PyQt the same?

The key difference in the two versions — in fact the entire reason PySide2 exists — is licensing. PyQt5 is available under a GPL or commercial license, and PySide2 under a LGPL license.

Can PyQt be used for commercial applications?

Can I use PyQt for commercial applications? Yes. There is a common misunderstanding that you cannot use GPL licensed software in commercial applications. This isn't the case.

Is PyQt5 free for commercial use?

PyQt is free software developed by the British firm Riverbank Computing. It is available under similar terms to Qt versions older than 4.5; this means a variety of licenses including GNU General Public License (GPL) and commercial license, but not the GNU Lesser General Public License (LGPL).


1 Answers

The old behavior can be forced by calling this code, which I found after more searching. I'm not sure I understand why this is bad behavior that needed to be deprecated, but this does work.

I submit that this should not be the default behavior, and that properly catching exceptions is the correct way to program, but given the specific purpose of my programming, and my time constraints, I find it useful to have access to as an optional mode, as I can still see the python exception traces printed to the console, and won't lose any unsaved data because of an uncaught exception.

import sys

def my_excepthook(type, value, tback):
    # log the exception here

    # then call the default handler
    sys.__excepthook__(type, value, tback)

sys.excepthook = my_excepthook
like image 106
Vince W. Avatar answered Oct 31 '22 19:10

Vince W.