1import importlib
2import os
3from typing import Tuple, Callable
4
5aliases = {
6 'qt4': 'qt',
7 'gtk2': 'gtk',
8}
9
10backends = [
11 "qt",
12 "qt5",
13 "qt6",
14 "gtk",
15 "gtk2",
16 "gtk3",
17 "gtk4",
18 "tk",
19 "wx",
20 "pyglet",
21 "glut",
22 "osx",
23 "asyncio",
24]
25
26registered = {}
27
28def register(name, inputhook):
29 """Register the function *inputhook* as an event loop integration."""
30 registered[name] = inputhook
31
32
33class UnknownBackend(KeyError):
34 def __init__(self, name):
35 self.name = name
36
37 def __str__(self):
38 return ("No event loop integration for {!r}. "
39 "Supported event loops are: {}").format(self.name,
40 ', '.join(backends + sorted(registered)))
41
42
43def set_qt_api(gui):
44 """Sets the `QT_API` environment variable if it isn't already set."""
45
46 qt_api = os.environ.get("QT_API", None)
47
48 from IPython.external.qt_loaders import (
49 QT_API_PYQT,
50 QT_API_PYQT5,
51 QT_API_PYQT6,
52 QT_API_PYSIDE,
53 QT_API_PYSIDE2,
54 QT_API_PYSIDE6,
55 QT_API_PYQTv1,
56 loaded_api,
57 )
58
59 loaded = loaded_api()
60
61 qt_env2gui = {
62 QT_API_PYSIDE: "qt4",
63 QT_API_PYQTv1: "qt4",
64 QT_API_PYQT: "qt4",
65 QT_API_PYSIDE2: "qt5",
66 QT_API_PYQT5: "qt5",
67 QT_API_PYSIDE6: "qt6",
68 QT_API_PYQT6: "qt6",
69 }
70 if loaded is not None and gui != "qt":
71 if qt_env2gui[loaded] != gui:
72 print(
73 f"Cannot switch Qt versions for this session; will use {qt_env2gui[loaded]}."
74 )
75 return qt_env2gui[loaded]
76
77 if qt_api is not None and gui != "qt":
78 if qt_env2gui[qt_api] != gui:
79 print(
80 f'Request for "{gui}" will be ignored because `QT_API` '
81 f'environment variable is set to "{qt_api}"'
82 )
83 return qt_env2gui[qt_api]
84 else:
85 if gui == "qt5":
86 try:
87 import PyQt5 # noqa
88
89 os.environ["QT_API"] = "pyqt5"
90 except ImportError:
91 try:
92 import PySide2 # noqa
93
94 os.environ["QT_API"] = "pyside2"
95 except ImportError:
96 os.environ["QT_API"] = "pyqt5"
97 elif gui == "qt6":
98 try:
99 import PyQt6 # noqa
100
101 os.environ["QT_API"] = "pyqt6"
102 except ImportError:
103 try:
104 import PySide6 # noqa
105
106 os.environ["QT_API"] = "pyside6"
107 except ImportError:
108 os.environ["QT_API"] = "pyqt6"
109 elif gui == "qt":
110 # Don't set QT_API; let IPython logic choose the version.
111 if "QT_API" in os.environ.keys():
112 del os.environ["QT_API"]
113 else:
114 print(f'Unrecognized Qt version: {gui}. Should be "qt5", "qt6", or "qt".')
115 return
116
117 # Import it now so we can figure out which version it is.
118 from IPython.external.qt_for_kernel import QT_API
119
120 return qt_env2gui[QT_API]
121
122
123def get_inputhook_name_and_func(gui: str) -> Tuple[str, Callable]:
124 if gui in registered:
125 return gui, registered[gui]
126
127 if gui not in backends:
128 raise UnknownBackend(gui)
129
130 if gui in aliases:
131 return get_inputhook_name_and_func(aliases[gui])
132
133 gui_mod = gui
134 if gui.startswith("qt"):
135 gui = set_qt_api(gui)
136 gui_mod = "qt"
137
138 mod = importlib.import_module("IPython.terminal.pt_inputhooks." + gui_mod)
139 return gui, mod.inputhook