From fd32adbcfa084c0217d5ff7ecd0fea44dce8bdd1 2017-01-12 15:16:13 From: Thomas Kluyver Date: 2017-01-12 15:16:13 Subject: [PATCH] New implementation of has_binding Qt check for Python 3.4+ Closes gh-10080 --- diff --git a/IPython/external/qt_loaders.py b/IPython/external/qt_loaders.py index 860a570..e16cb2a 100644 --- a/IPython/external/qt_loaders.py +++ b/IPython/external/qt_loaders.py @@ -21,6 +21,15 @@ QT_API_PYQT5 = 'pyqt5' QT_API_PYQTv1 = 'pyqtv1' # Force version 2 QT_API_PYQT_DEFAULT = 'pyqtdefault' # use system default for version 1 vs. 2 QT_API_PYSIDE = 'pyside' +QT_API_PYSIDE2 = 'pyside2' + +api_to_module = {QT_API_PYSIDE2: 'PySide2', + QT_API_PYSIDE: 'PySide', + QT_API_PYQT: 'PyQt4', + QT_API_PYQTv1: 'PyQt4', + QT_API_PYQT5: 'PyQt5', + QT_API_PYQT_DEFAULT: 'PyQt4', + } class ImportDenier(object): @@ -89,8 +98,9 @@ def loaded_api(): def has_binding(api): - """Safely check for PyQt4/5 or PySide, without importing - submodules + """Safely check for PyQt4/5 or PySide, without importing submodules + + Supports Python <= 3.3 Parameters ---------- @@ -104,12 +114,7 @@ def has_binding(api): # we can't import an incomplete pyside and pyqt4 # this will cause a crash in sip (#1431) # check for complete presence before importing - module_name = {QT_API_PYSIDE: 'PySide', - QT_API_PYQT: 'PyQt4', - QT_API_PYQTv1: 'PyQt4', - QT_API_PYQT5: 'PyQt5', - QT_API_PYQT_DEFAULT: 'PyQt4'} - module_name = module_name[api] + module_name = api_to_module[api] import imp try: @@ -131,6 +136,48 @@ def has_binding(api): except ImportError: return False +def has_binding_new(api): + """Safely check for PyQt4/5 or PySide, without importing submodules + + Supports Python >= 3.4 + + Parameters + ---------- + api : str [ 'pyqtv1' | 'pyqt' | 'pyqt5' | 'pyside' | 'pyqtdefault'] + Which module to check for + + Returns + ------- + True if the relevant module appears to be importable + """ + module_name = api_to_module[api] + from importlib.util import find_spec + + required = ['QtCore', 'QtGui', 'QtSvg'] + if api in (QT_API_PYQT5, QT_API_PYSIDE2): + # QT5 requires QtWidgets too + required.append('QtWidgets') + + for submod in required: + try: + spec = find_spec('%s.%s' % (module_name, submod)) + except ImportError: + # Package (e.g. PyQt5) not found + return False + else: + if spec is None: + # Submodule (e.g. PyQt5.QtCore) not found + return False + + if api == QT_API_PYSIDE: + # We can also safely check PySide version + import PySide + return check_version(PySide.__version__, '1.0.3') + + return True + +if sys.version_info >= (3, 4): + has_binding = has_binding_new def qtapi_version(): """Return which QString API has been set, if any