Show More
@@ -10,6 +10,7 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 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 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 |
|
|
921 | print( | |
918 |
f"Shell |
|
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 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 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; |
|
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 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 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 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 _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