Merge pull request #1618 from pijyoi/pyqt6_abort
PyQt6 install sys.excepthook
This commit is contained in:
commit
829f07b24a
150
pyqtgraph/Qt.py
150
pyqtgraph/Qt.py
@ -11,7 +11,6 @@ This module exists to smooth out some of the differences between PySide and PyQt
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os, sys, re, time, subprocess, warnings
|
import os, sys, re, time, subprocess, warnings
|
||||||
import importlib
|
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
from .python2_3 import asUnicode
|
from .python2_3 import asUnicode
|
||||||
@ -28,9 +27,10 @@ QT_LIB = os.getenv('PYQTGRAPH_QT_LIB')
|
|||||||
## Automatically determine which Qt package to use (unless specified by
|
## Automatically determine which Qt package to use (unless specified by
|
||||||
## environment variable).
|
## environment variable).
|
||||||
## This is done by first checking to see whether one of the libraries
|
## This is done by first checking to see whether one of the libraries
|
||||||
## is already imported. If not, then attempt to import PyQt4, then PySide.
|
## is already imported. If not, then attempt to import in the order
|
||||||
|
## specified in libOrder.
|
||||||
if QT_LIB is None:
|
if QT_LIB is None:
|
||||||
libOrder = [PYQT4, PYSIDE, PYQT5, PYSIDE2, PYSIDE6, PYQT6]
|
libOrder = [PYQT5, PYSIDE2, PYSIDE6, PYQT6]
|
||||||
|
|
||||||
for lib in libOrder:
|
for lib in libOrder:
|
||||||
if lib in sys.modules:
|
if lib in sys.modules:
|
||||||
@ -47,7 +47,7 @@ if QT_LIB is None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if QT_LIB is None:
|
if QT_LIB is None:
|
||||||
raise Exception("PyQtGraph requires one of PyQt4, PyQt5, PyQt6, PySide, PySide2 or PySide6; none of these packages could be imported.")
|
raise Exception("PyQtGraph requires one of PyQt5, PyQt6, PySide2 or PySide6; none of these packages could be imported.")
|
||||||
|
|
||||||
|
|
||||||
class FailedImport(object):
|
class FailedImport(object):
|
||||||
@ -60,22 +60,6 @@ class FailedImport(object):
|
|||||||
raise self.err
|
raise self.err
|
||||||
|
|
||||||
|
|
||||||
def _isQObjectAlive(obj):
|
|
||||||
"""An approximation of PyQt's isQObjectAlive().
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if hasattr(obj, 'parent'):
|
|
||||||
obj.parent()
|
|
||||||
elif hasattr(obj, 'parentItem'):
|
|
||||||
obj.parentItem()
|
|
||||||
else:
|
|
||||||
raise Exception("Cannot determine whether Qt object %s is still alive." % obj)
|
|
||||||
except RuntimeError:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
# Make a loadUiType function like PyQt has
|
# Make a loadUiType function like PyQt has
|
||||||
|
|
||||||
# Credit:
|
# Credit:
|
||||||
@ -106,14 +90,18 @@ def _loadUiType(uiFile):
|
|||||||
http://stackoverflow.com/a/8717832
|
http://stackoverflow.com/a/8717832
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if QT_LIB == "PYSIDE":
|
pyside2uic = None
|
||||||
import pysideuic
|
if QT_LIB == PYSIDE2:
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
import pyside2uic as pysideuic
|
import pyside2uic
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# later vserions of pyside2 have dropped pysideuic; use the uic binary instead.
|
# later versions of pyside2 have dropped pyside2uic; use the uic binary instead.
|
||||||
pysideuic = None
|
pyside2uic = None
|
||||||
|
|
||||||
|
if pyside2uic is None:
|
||||||
|
pyside2version = tuple(map(int, PySide2.__version__.split(".")))
|
||||||
|
if (5, 14) <= pyside2version < (5, 14, 2, 2):
|
||||||
|
warnings.warn('For UI compilation, it is recommended to upgrade to PySide >= 5.15')
|
||||||
|
|
||||||
# get class names from ui file
|
# get class names from ui file
|
||||||
import xml.etree.ElementTree as xml
|
import xml.etree.ElementTree as xml
|
||||||
@ -122,20 +110,16 @@ def _loadUiType(uiFile):
|
|||||||
form_class = parsed.find('class').text
|
form_class = parsed.find('class').text
|
||||||
|
|
||||||
# convert ui file to python code
|
# convert ui file to python code
|
||||||
if pysideuic is None:
|
if pyside2uic is None:
|
||||||
if QT_LIB == PYSIDE2:
|
|
||||||
pyside2version = tuple(map(int, PySide2.__version__.split(".")))
|
|
||||||
if pyside2version >= (5, 14) and pyside2version < (5, 14, 2, 2):
|
|
||||||
warnings.warn('For UI compilation, it is recommended to upgrade to PySide >= 5.15')
|
|
||||||
uic_executable = QT_LIB.lower() + '-uic'
|
uic_executable = QT_LIB.lower() + '-uic'
|
||||||
uipy = subprocess.check_output([uic_executable, uiFile])
|
uipy = subprocess.check_output([uic_executable, uiFile])
|
||||||
else:
|
else:
|
||||||
o = _StringIO()
|
o = _StringIO()
|
||||||
with open(uiFile, 'r') as f:
|
with open(uiFile, 'r') as f:
|
||||||
pysideuic.compileUi(f, o, indent=0)
|
pyside2uic.compileUi(f, o, indent=0)
|
||||||
uipy = o.getvalue()
|
uipy = o.getvalue()
|
||||||
|
|
||||||
# exceute python code
|
# execute python code
|
||||||
pyc = compile(uipy, '<string>', 'exec')
|
pyc = compile(uipy, '<string>', 'exec')
|
||||||
frame = {}
|
frame = {}
|
||||||
exec(pyc, frame)
|
exec(pyc, frame)
|
||||||
@ -147,65 +131,10 @@ def _loadUiType(uiFile):
|
|||||||
return form_class, base_class
|
return form_class, base_class
|
||||||
|
|
||||||
|
|
||||||
if QT_LIB == PYSIDE:
|
if QT_LIB == PYQT5:
|
||||||
from PySide import QtGui, QtCore
|
|
||||||
|
|
||||||
try:
|
|
||||||
from PySide import QtOpenGL
|
|
||||||
except ImportError as err:
|
|
||||||
QtOpenGL = FailedImport(err)
|
|
||||||
try:
|
|
||||||
from PySide import QtSvg
|
|
||||||
except ImportError as err:
|
|
||||||
QtSvg = FailedImport(err)
|
|
||||||
|
|
||||||
try:
|
|
||||||
from PySide import QtTest
|
|
||||||
except ImportError as err:
|
|
||||||
QtTest = FailedImport(err)
|
|
||||||
|
|
||||||
try:
|
|
||||||
from PySide import shiboken
|
|
||||||
isQObjectAlive = shiboken.isValid
|
|
||||||
except ImportError:
|
|
||||||
# use approximate version
|
|
||||||
isQObjectAlive = _isQObjectAlive
|
|
||||||
|
|
||||||
import PySide
|
|
||||||
VERSION_INFO = 'PySide ' + PySide.__version__ + ' Qt ' + QtCore.__version__
|
|
||||||
|
|
||||||
elif QT_LIB == PYQT4:
|
|
||||||
from PyQt4 import QtGui, QtCore, uic
|
|
||||||
try:
|
|
||||||
from PyQt4 import QtSvg
|
|
||||||
except ImportError as err:
|
|
||||||
QtSvg = FailedImport(err)
|
|
||||||
try:
|
|
||||||
from PyQt4 import QtOpenGL
|
|
||||||
except ImportError as err:
|
|
||||||
QtOpenGL = FailedImport(err)
|
|
||||||
try:
|
|
||||||
from PyQt4 import QtTest
|
|
||||||
except ImportError as err:
|
|
||||||
QtTest = FailedImport(err)
|
|
||||||
|
|
||||||
VERSION_INFO = 'PyQt4 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
|
|
||||||
|
|
||||||
elif QT_LIB == PYQT5:
|
|
||||||
# We're using PyQt5 which has a different structure so we're going to use a shim to
|
# We're using PyQt5 which has a different structure so we're going to use a shim to
|
||||||
# recreate the Qt4 structure for Qt5
|
# recreate the Qt4 structure for Qt5
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets, uic
|
from PyQt5 import QtGui, QtCore, QtWidgets, sip, uic
|
||||||
|
|
||||||
# PyQt5, starting in v5.5, calls qAbort when an exception is raised inside
|
|
||||||
# a slot. To maintain backward compatibility (and sanity for interactive
|
|
||||||
# users), we install a global exception hook to override this behavior.
|
|
||||||
ver = QtCore.PYQT_VERSION_STR.split('.')
|
|
||||||
if int(ver[1]) >= 5:
|
|
||||||
if sys.excepthook == sys.__excepthook__:
|
|
||||||
sys_excepthook = sys.excepthook
|
|
||||||
def pyqt5_qabort_override(*args, **kwds):
|
|
||||||
return sys_excepthook(*args, **kwds)
|
|
||||||
sys.excepthook = pyqt5_qabort_override
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtSvg
|
from PyQt5 import QtSvg
|
||||||
@ -219,7 +148,7 @@ elif QT_LIB == PYQT5:
|
|||||||
VERSION_INFO = 'PyQt5 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
|
VERSION_INFO = 'PyQt5 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
|
||||||
|
|
||||||
elif QT_LIB == PYQT6:
|
elif QT_LIB == PYQT6:
|
||||||
from PyQt6 import QtGui, QtCore, QtWidgets, uic
|
from PyQt6 import QtGui, QtCore, QtWidgets, sip, uic
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PyQt6 import QtSvg
|
from PyQt6 import QtSvg
|
||||||
@ -248,12 +177,8 @@ elif QT_LIB == PYSIDE2:
|
|||||||
except ImportError as err:
|
except ImportError as err:
|
||||||
QtTest = FailedImport(err)
|
QtTest = FailedImport(err)
|
||||||
|
|
||||||
try:
|
import shiboken2
|
||||||
import shiboken2
|
isQObjectAlive = shiboken2.isValid
|
||||||
isQObjectAlive = shiboken2.isValid
|
|
||||||
except ImportError:
|
|
||||||
# use approximate version
|
|
||||||
isQObjectAlive = _isQObjectAlive
|
|
||||||
import PySide2
|
import PySide2
|
||||||
VERSION_INFO = 'PySide2 ' + PySide2.__version__ + ' Qt ' + QtCore.__version__
|
VERSION_INFO = 'PySide2 ' + PySide2.__version__ + ' Qt ' + QtCore.__version__
|
||||||
|
|
||||||
@ -273,12 +198,8 @@ elif QT_LIB == PYSIDE6:
|
|||||||
except ImportError as err:
|
except ImportError as err:
|
||||||
QtTest = FailedImport(err)
|
QtTest = FailedImport(err)
|
||||||
|
|
||||||
try:
|
import shiboken6
|
||||||
import shiboken6
|
isQObjectAlive = shiboken6.isValid
|
||||||
isQObjectAlive = shiboken6.isValid
|
|
||||||
except ImportError:
|
|
||||||
# use approximate version
|
|
||||||
isQObjectAlive = _isQObjectAlive
|
|
||||||
import PySide6
|
import PySide6
|
||||||
VERSION_INFO = 'PySide6 ' + PySide6.__version__ + ' Qt ' + QtCore.__version__
|
VERSION_INFO = 'PySide6 ' + PySide6.__version__ + ' Qt ' + QtCore.__version__
|
||||||
|
|
||||||
@ -360,11 +281,11 @@ if QT_LIB in [PYQT6, PYSIDE6]:
|
|||||||
QtWidgets.QOpenGLWidget = QtOpenGLWidgets.QOpenGLWidget
|
QtWidgets.QOpenGLWidget = QtOpenGLWidgets.QOpenGLWidget
|
||||||
|
|
||||||
|
|
||||||
# Common to PySide, PySide2 and PySide6
|
# Common to PySide2 and PySide6
|
||||||
if QT_LIB in [PYSIDE, PYSIDE2, PYSIDE6]:
|
if QT_LIB in [PYSIDE2, PYSIDE6]:
|
||||||
QtVersion = QtCore.__version__
|
QtVersion = QtCore.__version__
|
||||||
loadUiType = _loadUiType
|
loadUiType = _loadUiType
|
||||||
|
|
||||||
# PySide does not implement qWait
|
# PySide does not implement qWait
|
||||||
if not isinstance(QtTest, FailedImport):
|
if not isinstance(QtTest, FailedImport):
|
||||||
if not hasattr(QtTest.QTest, 'qWait'):
|
if not hasattr(QtTest.QTest, 'qWait'):
|
||||||
@ -377,14 +298,19 @@ if QT_LIB in [PYSIDE, PYSIDE2, PYSIDE6]:
|
|||||||
QtTest.QTest.qWait = qWait
|
QtTest.QTest.qWait = qWait
|
||||||
|
|
||||||
|
|
||||||
# Common to PyQt4, PyQt5 and PyQt6
|
# Common to PyQt5 and PyQt6
|
||||||
if QT_LIB in [PYQT4, PYQT5, PYQT6]:
|
if QT_LIB in [PYQT5, PYQT6]:
|
||||||
QtVersion = QtCore.QT_VERSION_STR
|
QtVersion = QtCore.QT_VERSION_STR
|
||||||
|
|
||||||
|
# PyQt, starting in v5.5, calls qAbort when an exception is raised inside
|
||||||
|
# a slot. To maintain backward compatibility (and sanity for interactive
|
||||||
|
# users), we install a global exception hook to override this behavior.
|
||||||
|
if sys.excepthook == sys.__excepthook__:
|
||||||
|
sys_excepthook = sys.excepthook
|
||||||
|
def pyqt_qabort_override(*args, **kwds):
|
||||||
|
return sys_excepthook(*args, **kwds)
|
||||||
|
sys.excepthook = pyqt_qabort_override
|
||||||
|
|
||||||
try:
|
|
||||||
sip = importlib.import_module(QT_LIB + '.sip')
|
|
||||||
except ModuleNotFoundError:
|
|
||||||
import sip
|
|
||||||
def isQObjectAlive(obj):
|
def isQObjectAlive(obj):
|
||||||
return not sip.isdeleted(obj)
|
return not sip.isdeleted(obj)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user