From 4d707a61fa42eccdf842b8b1aa506a8036648471 2023-01-03 12:43:16 From: Emilio Graff <1@emil.io> Date: 2023-01-03 12:43:16 Subject: [PATCH] Bring in Qt import logic from `ipykernel` See https://github.com/ipython/ipykernel/pull/1054 --- diff --git a/IPython/terminal/pt_inputhooks/__init__.py b/IPython/terminal/pt_inputhooks/__init__.py index 8ae82f1..1d29e98 100644 --- a/IPython/terminal/pt_inputhooks/__init__.py +++ b/IPython/terminal/pt_inputhooks/__init__.py @@ -40,6 +40,82 @@ class UnknownBackend(KeyError): ', '.join(backends + sorted(registered))) +def set_qt_api(gui): + """Sets the `QT_API` environment variable if it isn't already set.""" + # TODO: how do we do this here? + # if hasattr(kernel, "app"): + # raise RuntimeError("Kernel already running a Qt event loop.") + + # if gui != "qt" and hasattr(kernel, "last_qt_version"): + # if kernel.last_qt_version != gui: + # raise ValueError( + # "Cannot switch Qt versions for this session; " + # f"must use {kernel.last_qt_version}." + # ) + + qt_api = os.environ.get("QT_API", None) + if qt_api is not None and gui != "qt": + env2gui = { + "pyside": "qt4", + "pyqt": "qt4", + "pyside2": "qt5", + "pyqt5": "qt5", + "pyside6": "qt6", + "pyqt6": "qt6", + } + if env2gui[qt_api] != gui: + print( + f'Request for "{gui}" will be ignored because `QT_API` ' + f'environment variable is set to "{qt_api}"' + ) + else: + if gui == "qt4": + try: + import PyQt # noqa + + os.environ["QT_API"] = "pyqt" + except ImportError: + try: + import PySide # noqa + + os.environ["QT_API"] = "pyside" + except ImportError: + # Neither implementation installed; set it to something so IPython gives an error + os.environ["QT_API"] = "pyqt" + elif gui == "qt5": + try: + import PyQt5 # noqa + + os.environ["QT_API"] = "pyqt5" + except ImportError: + try: + import PySide2 # noqa + + os.environ["QT_API"] = "pyside2" + except ImportError: + os.environ["QT_API"] = "pyqt5" + elif gui == "qt6": + try: + import PyQt6 # noqa + + os.environ["QT_API"] = "pyqt6" + except ImportError: + try: + import PySide6 # noqa + + os.environ["QT_API"] = "pyside6" + except ImportError: + os.environ["QT_API"] = "pyqt6" + elif gui == "qt": + # Don't set QT_API; let IPython logic choose the version. + if "QT_API" in os.environ.keys(): + del os.environ["QT_API"] + else: + raise ValueError( + f'Unrecognized Qt version: {gui}. Should be "qt4", "qt5", "qt6", or "qt".' + ) + + def get_inputhook_name_and_func(gui): print(f'`get_inputhook_name_and_func` called with {gui=}') if gui in registered: @@ -49,20 +125,13 @@ def get_inputhook_name_and_func(gui): raise UnknownBackend(gui) if gui in aliases: + print('gui has an alias') return get_inputhook_name_and_func(aliases[gui]) gui_mod = gui - if gui == "qt5": - os.environ["QT_API"] = "pyqt5" - gui_mod = "qt" - elif gui == "qt6": - # XXX: this locks us into pyqt6 even if pyside6 is installed. - os.environ["QT_API"] = "pyqt6" + if gui.startswith("qt"): + set_qt_api(gui) gui_mod = "qt" - print(f'{gui_mod=}') - # Note: `IPython.terminal.pt_inputhooks.qt` imports `IPython.external.qt_for_kernel` and that's - # where the environment variable locks us into `pyqt6`, despite the fact that it seems `PySide6` - # is supported. - mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui_mod) + mod = importlib.import_module("IPython.terminal.pt_inputhooks." + gui_mod) return gui, mod.inputhook