##// END OF EJS Templates
Shaperilio/qtgui fixes (#13957)...
Matthias Bussonnier -
r28163:88d1fedc merge
parent child Browse files
Show More
@@ -10,6 +10,7 b' be accessed directly from the outside'
10 """
10 """
11 import importlib.abc
11 import importlib.abc
12 import sys
12 import sys
13 import os
13 import types
14 import types
14 from functools import partial, lru_cache
15 from functools import partial, lru_cache
15 import operator
16 import operator
@@ -368,6 +369,10 b' def load_qt(api_options):'
368 commit_api(api)
369 commit_api(api)
369 return result
370 return result
370 else:
371 else:
372 # Clear the environment variable since it doesn't work.
373 if "QT_API" in os.environ:
374 del os.environ["QT_API"]
375
371 raise ImportError(
376 raise ImportError(
372 """
377 """
373 Could not load requested Qt binding. Please ensure that
378 Could not load requested Qt binding. Please ensure that
@@ -913,10 +913,19 b' class TerminalInteractiveShell(InteractiveShell):'
913
913
914 active_eventloop = None
914 active_eventloop = None
915 def enable_gui(self, gui=None):
915 def enable_gui(self, gui=None):
916 if self._inputhook is None and gui is None:
917 print("No event loop hook running.")
918 return
919
916 if self._inputhook is not None and gui is not None:
920 if self._inputhook is not None and gui is not None:
917 warn(
921 print(
918 f"Shell was already running a gui event loop for {self.active_eventloop}; switching to {gui}."
922 f"Shell is already running a gui event loop for {self.active_eventloop}. "
923 "Call with no arguments to disable the current loop."
919 )
924 )
925 return
926 if self._inputhook is not None and gui is None:
927 self.active_eventloop = self._inputhook = None
928
920 if gui and (gui not in {"inline", "webagg"}):
929 if gui and (gui not in {"inline", "webagg"}):
921 # This hook runs with each cycle of the `prompt_toolkit`'s event loop.
930 # This hook runs with each cycle of the `prompt_toolkit`'s event loop.
922 self.active_eventloop, self._inputhook = get_inputhook_name_and_func(gui)
931 self.active_eventloop, self._inputhook = get_inputhook_name_and_func(gui)
@@ -934,15 +943,18 b' class TerminalInteractiveShell(InteractiveShell):'
934 # same event loop as the rest of the code. don't use an actual
943 # same event loop as the rest of the code. don't use an actual
935 # input hook. (Asyncio is not made for nesting event loops.)
944 # input hook. (Asyncio is not made for nesting event loops.)
936 self.pt_loop = get_asyncio_loop()
945 self.pt_loop = get_asyncio_loop()
946 print("Installed asyncio event loop hook.")
937
947
938 elif self._inputhook:
948 elif self._inputhook:
939 # If an inputhook was set, create a new asyncio event loop with
949 # If an inputhook was set, create a new asyncio event loop with
940 # this inputhook for the prompt.
950 # this inputhook for the prompt.
941 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
951 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
952 print(f"Installed {self.active_eventloop} event loop hook.")
942 else:
953 else:
943 # When there's no inputhook, run the prompt in a separate
954 # When there's no inputhook, run the prompt in a separate
944 # asyncio event loop.
955 # asyncio event loop.
945 self.pt_loop = asyncio.new_event_loop()
956 self.pt_loop = asyncio.new_event_loop()
957 print("GUI event loop hook disabled.")
946
958
947 # Run !system commands directly, not through pipes, so terminal programs
959 # Run !system commands directly, not through pipes, so terminal programs
948 # work correctly.
960 # work correctly.
@@ -69,9 +69,9 b' def set_qt_api(gui):'
69 if loaded is not None and gui != "qt":
69 if loaded is not None and gui != "qt":
70 if qt_env2gui[loaded] != gui:
70 if qt_env2gui[loaded] != gui:
71 print(
71 print(
72 f"Cannot switch Qt versions for this session; must use {qt_env2gui[loaded]}."
72 f"Cannot switch Qt versions for this session; will use {qt_env2gui[loaded]}."
73 )
73 )
74 return
74 return qt_env2gui[loaded]
75
75
76 if qt_api is not None and gui != "qt":
76 if qt_api is not None and gui != "qt":
77 if qt_env2gui[qt_api] != gui:
77 if qt_env2gui[qt_api] != gui:
@@ -79,6 +79,7 b' def set_qt_api(gui):'
79 f'Request for "{gui}" will be ignored because `QT_API` '
79 f'Request for "{gui}" will be ignored because `QT_API` '
80 f'environment variable is set to "{qt_api}"'
80 f'environment variable is set to "{qt_api}"'
81 )
81 )
82 return qt_env2gui[qt_api]
82 else:
83 else:
83 if gui == "qt5":
84 if gui == "qt5":
84 try:
85 try:
@@ -112,6 +113,11 b' def set_qt_api(gui):'
112 print(f'Unrecognized Qt version: {gui}. Should be "qt5", "qt6", or "qt".')
113 print(f'Unrecognized Qt version: {gui}. Should be "qt5", "qt6", or "qt".')
113 return
114 return
114
115
116 # Import it now so we can figure out which version it is.
117 from IPython.external.qt_for_kernel import QT_API
118
119 return qt_env2gui[QT_API]
120
115
121
116 def get_inputhook_name_and_func(gui):
122 def get_inputhook_name_and_func(gui):
117 if gui in registered:
123 if gui in registered:
@@ -125,7 +131,7 b' def get_inputhook_name_and_func(gui):'
125
131
126 gui_mod = gui
132 gui_mod = gui
127 if gui.startswith("qt"):
133 if gui.startswith("qt"):
128 set_qt_api(gui)
134 gui = set_qt_api(gui)
129 gui_mod = "qt"
135 gui_mod = "qt"
130
136
131 mod = importlib.import_module("IPython.terminal.pt_inputhooks." + gui_mod)
137 mod = importlib.import_module("IPython.terminal.pt_inputhooks." + gui_mod)
@@ -33,18 +33,18 b' _get_qt_vers()'
33 len(guis_avail) == 0, reason="No viable version of PyQt or PySide installed."
33 len(guis_avail) == 0, reason="No viable version of PyQt or PySide installed."
34 )
34 )
35 def test_inputhook_qt():
35 def test_inputhook_qt():
36 gui = guis_avail[0]
36 # Choose the "best" Qt version.
37
37 gui_ret, _ = get_inputhook_name_and_func("qt")
38 # Choose a qt version and get the input hook function. This will import Qt...
38
39 get_inputhook_name_and_func(gui)
39 assert gui_ret != "qt" # you get back the specific version that was loaded.
40
40 assert gui_ret in guis_avail
41 # ...and now we're stuck with this version of Qt for good; can't switch.
41
42 for not_gui in ["qt6", "qt5"]:
42 if len(guis_avail) > 2:
43 if not_gui not in guis_avail:
43 # ...and now we're stuck with this version of Qt for good; can't switch.
44 break
44 for not_gui in ["qt6", "qt5"]:
45
45 if not_gui != gui_ret:
46 with pytest.raises(ImportError):
46 break
47 get_inputhook_name_and_func(not_gui)
47 # Try to import the other gui; it won't work.
48
48 gui_ret2, _ = get_inputhook_name_and_func(not_gui)
49 # A gui of 'qt' means "best available", or in this case, the last one that was used.
49 assert gui_ret2 == gui_ret
50 get_inputhook_name_and_func("qt")
50 assert gui_ret2 != not_gui
General Comments 0
You need to be logged in to leave comments. Login now