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