Show More
@@ -13,55 +13,53 b' class BaseFrontendMixin(object):' | |||||
13 | # 'BaseFrontendMixin' concrete interface |
|
13 | # 'BaseFrontendMixin' concrete interface | |
14 | #--------------------------------------------------------------------------- |
|
14 | #--------------------------------------------------------------------------- | |
15 |
|
15 | |||
16 |
def _get_kernel_ |
|
16 | def _get_kernel_client(self): | |
17 |
""" |
|
17 | """Returns the current kernel client. | |
18 | """ |
|
18 | """ | |
19 |
return self._kernel_ |
|
19 | return self._kernel_client | |
20 |
|
20 | |||
21 |
def _set_kernel_ |
|
21 | def _set_kernel_client(self, kernel_client): | |
22 |
""" |
|
22 | """Disconnect from the current kernel client (if any) and set a new | |
23 |
kernel |
|
23 | kernel client. | |
24 | """ |
|
24 | """ | |
25 |
# Disconnect the old kernel |
|
25 | # Disconnect the old kernel client, if necessary. | |
26 |
old_ |
|
26 | old_client = self._kernel_client | |
27 |
if old_ |
|
27 | if old_client is not None: | |
28 |
old_ |
|
28 | old_client.started_channels.disconnect(self._started_channels) | |
29 |
old_ |
|
29 | old_client.stopped_channels.disconnect(self._stopped_channels) | |
30 | old_manager.stopped_channels.disconnect(self._stopped_channels) |
|
30 | ||
31 |
|
31 | # Disconnect the old kernel client's channels. | ||
32 | # Disconnect the old kernel manager's channels. |
|
32 | old_client.iopub_channel.message_received.disconnect(self._dispatch) | |
33 |
old_ |
|
33 | old_client.shell_channel.message_received.disconnect(self._dispatch) | |
34 |
old_ |
|
34 | old_client.stdin_channel.message_received.disconnect(self._dispatch) | |
35 |
old_ |
|
35 | old_client.hb_channel.kernel_died.disconnect( | |
36 | old_manager.hb_channel.kernel_died.disconnect( |
|
|||
37 | self._handle_kernel_died) |
|
36 | self._handle_kernel_died) | |
38 |
|
37 | |||
39 |
# Handle the case where the old kernel |
|
38 | # Handle the case where the old kernel client is still listening. | |
40 |
if old_ |
|
39 | if old_client.channels_running: | |
41 | self._stopped_channels() |
|
40 | self._stopped_channels() | |
42 |
|
41 | |||
43 |
# Set the new kernel |
|
42 | # Set the new kernel client. | |
44 |
self._kernel_ |
|
43 | self._kernel_client = kernel_client | |
45 |
if kernel_ |
|
44 | if kernel_client is None: | |
46 | return |
|
45 | return | |
47 |
|
46 | |||
48 |
# Connect the new kernel |
|
47 | # Connect the new kernel client. | |
49 |
kernel_ |
|
48 | kernel_client.started_channels.connect(self._started_channels) | |
50 |
kernel_ |
|
49 | kernel_client.stopped_channels.connect(self._stopped_channels) | |
51 | kernel_manager.stopped_channels.connect(self._stopped_channels) |
|
|||
52 |
|
50 | |||
53 |
# Connect the new kernel |
|
51 | # Connect the new kernel client's channels. | |
54 |
kernel_ |
|
52 | kernel_client.iopub_channel.message_received.connect(self._dispatch) | |
55 |
kernel_ |
|
53 | kernel_client.shell_channel.message_received.connect(self._dispatch) | |
56 |
kernel_ |
|
54 | kernel_client.stdin_channel.message_received.connect(self._dispatch) | |
57 |
kernel_ |
|
55 | kernel_client.hb_channel.kernel_died.connect(self._handle_kernel_died) | |
58 |
|
56 | |||
59 |
# Handle the case where the kernel |
|
57 | # Handle the case where the kernel client started channels before | |
60 | # we connected. |
|
58 | # we connected. | |
61 |
if kernel_ |
|
59 | if kernel_client.channels_running: | |
62 | self._started_channels() |
|
60 | self._started_channels() | |
63 |
|
61 | |||
64 |
kernel_ |
|
62 | kernel_client = property(_get_kernel_client, _set_kernel_client) | |
65 |
|
63 | |||
66 | #--------------------------------------------------------------------------- |
|
64 | #--------------------------------------------------------------------------- | |
67 | # 'BaseFrontendMixin' abstract interface |
|
65 | # 'BaseFrontendMixin' abstract interface | |
@@ -112,7 +110,7 b' class BaseFrontendMixin(object):' | |||||
112 | """ Returns whether a reply from the kernel originated from a request |
|
110 | """ Returns whether a reply from the kernel originated from a request | |
113 | from this frontend. |
|
111 | from this frontend. | |
114 | """ |
|
112 | """ | |
115 |
session = self._kernel_ |
|
113 | session = self._kernel_client.session.session | |
116 | parent = msg['parent_header'] |
|
114 | parent = msg['parent_header'] | |
117 | if not parent: |
|
115 | if not parent: | |
118 | # if the message has no parent, assume it is meant for all frontends |
|
116 | # if the message has no parent, assume it is meant for all frontends |
@@ -1,13 +1,18 b'' | |||||
1 |
""" Defines a Kernel |
|
1 | """ Defines a KernelClient that provides signals and slots. | |
2 | """ |
|
2 | """ | |
3 |
|
3 | |||
4 |
# Local imports |
|
4 | # Local imports | |
5 | from IPython.utils.traitlets import Type |
|
5 | from IPython.utils.traitlets import Type | |
6 | from IPython.kernel.kernelmanager import ShellChannel, IOPubChannel, \ |
|
6 | from IPython.kernel.channels import ( | |
7 | StdInChannel, HBChannel, KernelManager |
|
7 | ShellChannel, IOPubChannel, StdInChannel, HBChannel | |
8 | from base_kernelmanager import QtShellChannelMixin, QtIOPubChannelMixin, \ |
|
8 | ) | |
9 | QtStdInChannelMixin, QtHBChannelMixin, QtKernelManagerMixin |
|
9 | from IPython.kernel import KernelClient | |
10 |
|
10 | |||
|
11 | from .kernel_mixins import ( | |||
|
12 | QtShellChannelMixin, QtIOPubChannelMixin, | |||
|
13 | QtStdInChannelMixin, QtHBChannelMixin, | |||
|
14 | QtKernelClientMixin | |||
|
15 | ) | |||
11 |
|
16 | |||
12 | class QtShellChannel(QtShellChannelMixin, ShellChannel): |
|
17 | class QtShellChannel(QtShellChannelMixin, ShellChannel): | |
13 | pass |
|
18 | pass | |
@@ -22,8 +27,8 b' class QtHBChannel(QtHBChannelMixin, HBChannel):' | |||||
22 | pass |
|
27 | pass | |
23 |
|
28 | |||
24 |
|
29 | |||
25 |
class QtKernel |
|
30 | class QtKernelClient(QtKernelClientMixin, KernelClient): | |
26 |
""" A Kernel |
|
31 | """ A KernelClient that provides signals and slots. | |
27 | """ |
|
32 | """ | |
28 |
|
33 | |||
29 | iopub_channel_class = Type(QtIOPubChannel) |
|
34 | iopub_channel_class = Type(QtIOPubChannel) |
@@ -148,6 +148,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
148 | self._highlighter = FrontendHighlighter(self) |
|
148 | self._highlighter = FrontendHighlighter(self) | |
149 | self._input_splitter = self._input_splitter_class() |
|
149 | self._input_splitter = self._input_splitter_class() | |
150 | self._kernel_manager = None |
|
150 | self._kernel_manager = None | |
|
151 | self._kernel_client = None | |||
151 | self._request_info = {} |
|
152 | self._request_info = {} | |
152 | self._request_info['execute'] = {}; |
|
153 | self._request_info['execute'] = {}; | |
153 | self._callback_dict = {} |
|
154 | self._callback_dict = {} | |
@@ -215,7 +216,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
215 |
|
216 | |||
216 | See parent class :meth:`execute` docstring for full details. |
|
217 | See parent class :meth:`execute` docstring for full details. | |
217 | """ |
|
218 | """ | |
218 |
msg_id = self.kernel_ |
|
219 | msg_id = self.kernel_client.shell_channel.execute(source, hidden) | |
219 | self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'user') |
|
220 | self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'user') | |
220 | self._hidden = hidden |
|
221 | self._hidden = hidden | |
221 | if not hidden: |
|
222 | if not hidden: | |
@@ -357,7 +358,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
357 | # generate uuid, which would be used as an indication of whether or |
|
358 | # generate uuid, which would be used as an indication of whether or | |
358 | # not the unique request originated from here (can use msg id ?) |
|
359 | # not the unique request originated from here (can use msg id ?) | |
359 | local_uuid = str(uuid.uuid1()) |
|
360 | local_uuid = str(uuid.uuid1()) | |
360 |
msg_id = self.kernel_ |
|
361 | msg_id = self.kernel_client.shell_channel.execute('', | |
361 | silent=True, user_expressions={ local_uuid:expr }) |
|
362 | silent=True, user_expressions={ local_uuid:expr }) | |
362 | self._callback_dict[local_uuid] = callback |
|
363 | self._callback_dict[local_uuid] = callback | |
363 | self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'silent_exec_callback') |
|
364 | self._request_info['execute'][msg_id] = self._ExecutionRequest(msg_id, 'silent_exec_callback') | |
@@ -400,7 +401,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
400 | if info and info.kind == 'user' and not self._hidden: |
|
401 | if info and info.kind == 'user' and not self._hidden: | |
401 | # Make sure that all output from the SUB channel has been processed |
|
402 | # Make sure that all output from the SUB channel has been processed | |
402 | # before writing a new prompt. |
|
403 | # before writing a new prompt. | |
403 |
self.kernel_ |
|
404 | self.kernel_client.iopub_channel.flush() | |
404 |
|
405 | |||
405 | # Reset the ANSI style information to prevent bad text in stdout |
|
406 | # Reset the ANSI style information to prevent bad text in stdout | |
406 | # from messing up our colors. We're not a true terminal so we're |
|
407 | # from messing up our colors. We're not a true terminal so we're | |
@@ -435,10 +436,10 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
435 |
|
436 | |||
436 | # Make sure that all output from the SUB channel has been processed |
|
437 | # Make sure that all output from the SUB channel has been processed | |
437 | # before entering readline mode. |
|
438 | # before entering readline mode. | |
438 |
self.kernel_ |
|
439 | self.kernel_client.iopub_channel.flush() | |
439 |
|
440 | |||
440 | def callback(line): |
|
441 | def callback(line): | |
441 |
self.kernel_ |
|
442 | self.kernel_client.stdin_channel.input(line) | |
442 | if self._reading: |
|
443 | if self._reading: | |
443 | self.log.debug("Got second input request, assuming first was interrupted.") |
|
444 | self.log.debug("Got second input request, assuming first was interrupted.") | |
444 | self._reading = False |
|
445 | self._reading = False | |
@@ -568,7 +569,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
568 | if self.custom_interrupt: |
|
569 | if self.custom_interrupt: | |
569 | self._reading = False |
|
570 | self._reading = False | |
570 | self.custom_interrupt_requested.emit() |
|
571 | self.custom_interrupt_requested.emit() | |
571 |
elif self.kernel_manager |
|
572 | elif self.kernel_manager: | |
572 | self._reading = False |
|
573 | self._reading = False | |
573 | self.kernel_manager.interrupt_kernel() |
|
574 | self.kernel_manager.interrupt_kernel() | |
574 | else: |
|
575 | else: | |
@@ -615,9 +616,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
615 | if self.custom_restart: |
|
616 | if self.custom_restart: | |
616 | self.custom_restart_requested.emit() |
|
617 | self.custom_restart_requested.emit() | |
617 |
|
618 | |||
618 |
elif self.kernel_manager |
|
619 | elif self.kernel_manager: | |
619 | # Pause the heart beat channel to prevent further warnings. |
|
620 | # Pause the heart beat channel to prevent further warnings. | |
620 |
self.kernel_ |
|
621 | self.kernel_client.hb_channel.pause() | |
621 |
|
622 | |||
622 | # Prompt the user to restart the kernel. Un-pause the heartbeat if |
|
623 | # Prompt the user to restart the kernel. Un-pause the heartbeat if | |
623 | # they decline. (If they accept, the heartbeat will be un-paused |
|
624 | # they decline. (If they accept, the heartbeat will be un-paused | |
@@ -642,7 +643,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
642 | else: |
|
643 | else: | |
643 | self.reset() |
|
644 | self.reset() | |
644 | else: |
|
645 | else: | |
645 |
self.kernel_ |
|
646 | self.kernel_client.hb_channel.unpause() | |
646 |
|
647 | |||
647 | else: |
|
648 | else: | |
648 | self._append_plain_text('Kernel process is either remote or ' |
|
649 | self._append_plain_text('Kernel process is either remote or ' | |
@@ -670,7 +671,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
670 |
|
671 | |||
671 | # Send the metadata request to the kernel |
|
672 | # Send the metadata request to the kernel | |
672 | name = '.'.join(context) |
|
673 | name = '.'.join(context) | |
673 |
msg_id = self.kernel_ |
|
674 | msg_id = self.kernel_client.shell_channel.object_info(name) | |
674 | pos = self._get_cursor().position() |
|
675 | pos = self._get_cursor().position() | |
675 | self._request_info['call_tip'] = self._CallTipRequest(msg_id, pos) |
|
676 | self._request_info['call_tip'] = self._CallTipRequest(msg_id, pos) | |
676 | return True |
|
677 | return True | |
@@ -681,7 +682,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
681 | context = self._get_context() |
|
682 | context = self._get_context() | |
682 | if context: |
|
683 | if context: | |
683 | # Send the completion request to the kernel |
|
684 | # Send the completion request to the kernel | |
684 |
msg_id = self.kernel_ |
|
685 | msg_id = self.kernel_client.shell_channel.complete( | |
685 | '.'.join(context), # text |
|
686 | '.'.join(context), # text | |
686 | self._get_input_buffer_cursor_line(), # line |
|
687 | self._get_input_buffer_cursor_line(), # line | |
687 | self._get_input_buffer_cursor_column(), # cursor_pos |
|
688 | self._get_input_buffer_cursor_column(), # cursor_pos |
@@ -224,7 +224,7 b' class HistoryConsoleWidget(ConsoleWidget):' | |||||
224 | return self._history[-n:] |
|
224 | return self._history[-n:] | |
225 |
|
225 | |||
226 | def _request_update_session_history_length(self): |
|
226 | def _request_update_session_history_length(self): | |
227 |
msg_id = self.kernel_ |
|
227 | msg_id = self.kernel_client.shell_channel.execute('', | |
228 | silent=True, |
|
228 | silent=True, | |
229 | user_expressions={ |
|
229 | user_expressions={ | |
230 | 'hlen':'len(get_ipython().history_manager.input_hist_raw)', |
|
230 | 'hlen':'len(get_ipython().history_manager.input_hist_raw)', |
@@ -194,7 +194,7 b' class IPythonWidget(FrontendWidget):' | |||||
194 | self._retrying_history_request = True |
|
194 | self._retrying_history_request = True | |
195 | # wait out the kernel's queue flush, which is currently timed at 0.1s |
|
195 | # wait out the kernel's queue flush, which is currently timed at 0.1s | |
196 | time.sleep(0.25) |
|
196 | time.sleep(0.25) | |
197 |
self.kernel_ |
|
197 | self.kernel_client.shell_channel.history(hist_access_type='tail',n=1000) | |
198 | else: |
|
198 | else: | |
199 | self._retrying_history_request = False |
|
199 | self._retrying_history_request = False | |
200 | return |
|
200 | return | |
@@ -261,7 +261,7 b' class IPythonWidget(FrontendWidget):' | |||||
261 | """Reimplemented to make a history request and load %guiref.""" |
|
261 | """Reimplemented to make a history request and load %guiref.""" | |
262 | super(IPythonWidget, self)._started_channels() |
|
262 | super(IPythonWidget, self)._started_channels() | |
263 | self._load_guiref_magic() |
|
263 | self._load_guiref_magic() | |
264 |
self.kernel_ |
|
264 | self.kernel_client.shell_channel.history(hist_access_type='tail', | |
265 | n=1000) |
|
265 | n=1000) | |
266 |
|
266 | |||
267 | def _started_kernel(self): |
|
267 | def _started_kernel(self): | |
@@ -269,12 +269,12 b' class IPythonWidget(FrontendWidget):' | |||||
269 |
|
269 | |||
270 | Principally triggered by kernel restart. |
|
270 | Principally triggered by kernel restart. | |
271 | """ |
|
271 | """ | |
272 |
if self.kernel_ |
|
272 | if self.kernel_client.shell_channel is not None: | |
273 | self._load_guiref_magic() |
|
273 | self._load_guiref_magic() | |
274 |
|
274 | |||
275 | def _load_guiref_magic(self): |
|
275 | def _load_guiref_magic(self): | |
276 | """Load %guiref magic.""" |
|
276 | """Load %guiref magic.""" | |
277 |
self.kernel_ |
|
277 | self.kernel_client.shell_channel.execute('\n'.join([ | |
278 | "try:", |
|
278 | "try:", | |
279 | " _usage", |
|
279 | " _usage", | |
280 | "except:", |
|
280 | "except:", | |
@@ -330,7 +330,7 b' class IPythonWidget(FrontendWidget):' | |||||
330 | text = '' |
|
330 | text = '' | |
331 |
|
331 | |||
332 | # Send the completion request to the kernel |
|
332 | # Send the completion request to the kernel | |
333 |
msg_id = self.kernel_ |
|
333 | msg_id = self.kernel_client.shell_channel.complete( | |
334 | text, # text |
|
334 | text, # text | |
335 | self._get_input_buffer_cursor_line(), # line |
|
335 | self._get_input_buffer_cursor_line(), # line | |
336 | self._get_input_buffer_cursor_column(), # cursor_pos |
|
336 | self._get_input_buffer_cursor_column(), # cursor_pos | |
@@ -376,7 +376,7 b' class IPythonWidget(FrontendWidget):' | |||||
376 | """ |
|
376 | """ | |
377 | # If a number was not specified, make a prompt number request. |
|
377 | # If a number was not specified, make a prompt number request. | |
378 | if number is None: |
|
378 | if number is None: | |
379 |
msg_id = self.kernel_ |
|
379 | msg_id = self.kernel_client.shell_channel.execute('', silent=True) | |
380 | info = self._ExecutionRequest(msg_id, 'prompt') |
|
380 | info = self._ExecutionRequest(msg_id, 'prompt') | |
381 | self._request_info['execute'][msg_id] = info |
|
381 | self._request_info['execute'][msg_id] = info | |
382 | return |
|
382 | return |
@@ -176,14 +176,14 b' class MainWindow(QtGui.QMainWindow):' | |||||
176 | self.update_tab_bar_visibility() |
|
176 | self.update_tab_bar_visibility() | |
177 | return |
|
177 | return | |
178 |
|
178 | |||
179 |
kernel_ |
|
179 | kernel_client = closing_widget.kernel_client | |
180 |
|
180 | |||
181 | if keepkernel is None and not closing_widget._confirm_exit: |
|
181 | if keepkernel is None and not closing_widget._confirm_exit: | |
182 | # don't prompt, just terminate the kernel if we own it |
|
182 | # don't prompt, just terminate the kernel if we own it | |
183 | # or leave it alone if we don't |
|
183 | # or leave it alone if we don't | |
184 | keepkernel = closing_widget._existing |
|
184 | keepkernel = closing_widget._existing | |
185 | if keepkernel is None: #show prompt |
|
185 | if keepkernel is None: #show prompt | |
186 |
if kernel_ |
|
186 | if kernel_client and kernel_client.channels_running: | |
187 | title = self.window().windowTitle() |
|
187 | title = self.window().windowTitle() | |
188 | cancel = QtGui.QMessageBox.Cancel |
|
188 | cancel = QtGui.QMessageBox.Cancel | |
189 | okay = QtGui.QMessageBox.Ok |
|
189 | okay = QtGui.QMessageBox.Ok | |
@@ -209,17 +209,17 b' class MainWindow(QtGui.QMainWindow):' | |||||
209 | reply = box.exec_() |
|
209 | reply = box.exec_() | |
210 | if reply == 1: # close All |
|
210 | if reply == 1: # close All | |
211 | for slave in slave_tabs: |
|
211 | for slave in slave_tabs: | |
212 |
background(slave.kernel_ |
|
212 | background(slave.kernel_client.stop_channels) | |
213 | self.tab_widget.removeTab(self.tab_widget.indexOf(slave)) |
|
213 | self.tab_widget.removeTab(self.tab_widget.indexOf(slave)) | |
214 | closing_widget.execute("exit") |
|
214 | closing_widget.execute("exit") | |
215 | self.tab_widget.removeTab(current_tab) |
|
215 | self.tab_widget.removeTab(current_tab) | |
216 |
background(kernel_ |
|
216 | background(kernel_client.stop_channels) | |
217 | elif reply == 0: # close Console |
|
217 | elif reply == 0: # close Console | |
218 | if not closing_widget._existing: |
|
218 | if not closing_widget._existing: | |
219 | # Have kernel: don't quit, just close the tab |
|
219 | # Have kernel: don't quit, just close the tab | |
220 | closing_widget.execute("exit True") |
|
220 | closing_widget.execute("exit True") | |
221 | self.tab_widget.removeTab(current_tab) |
|
221 | self.tab_widget.removeTab(current_tab) | |
222 |
background(kernel_ |
|
222 | background(kernel_client.stop_channels) | |
223 | else: |
|
223 | else: | |
224 | reply = QtGui.QMessageBox.question(self, title, |
|
224 | reply = QtGui.QMessageBox.question(self, title, | |
225 | "Are you sure you want to close this Console?"+ |
|
225 | "Are you sure you want to close this Console?"+ | |
@@ -231,15 +231,15 b' class MainWindow(QtGui.QMainWindow):' | |||||
231 | self.tab_widget.removeTab(current_tab) |
|
231 | self.tab_widget.removeTab(current_tab) | |
232 | elif keepkernel: #close console but leave kernel running (no prompt) |
|
232 | elif keepkernel: #close console but leave kernel running (no prompt) | |
233 | self.tab_widget.removeTab(current_tab) |
|
233 | self.tab_widget.removeTab(current_tab) | |
234 |
background(kernel_ |
|
234 | background(kernel_client.stop_channels) | |
235 | else: #close console and kernel (no prompt) |
|
235 | else: #close console and kernel (no prompt) | |
236 | self.tab_widget.removeTab(current_tab) |
|
236 | self.tab_widget.removeTab(current_tab) | |
237 |
if kernel_ |
|
237 | if kernel_client and kernel_client.channels_running: | |
238 | for slave in slave_tabs: |
|
238 | for slave in slave_tabs: | |
239 |
background(slave.kernel_ |
|
239 | background(slave.kernel_client.stop_channels) | |
240 | self.tab_widget.removeTab(self.tab_widget.indexOf(slave)) |
|
240 | self.tab_widget.removeTab(self.tab_widget.indexOf(slave)) | |
241 | kernel_manager.shutdown_kernel() |
|
241 | kernel_manager.shutdown_kernel() | |
242 |
background(kernel_ |
|
242 | background(kernel_client.stop_channels) | |
243 |
|
243 | |||
244 | self.update_tab_bar_visibility() |
|
244 | self.update_tab_bar_visibility() | |
245 |
|
245 | |||
@@ -284,7 +284,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
284 | #convert from/to int/richIpythonWidget if needed |
|
284 | #convert from/to int/richIpythonWidget if needed | |
285 | if isinstance(tab, int): |
|
285 | if isinstance(tab, int): | |
286 | tab = self.tab_widget.widget(tab) |
|
286 | tab = self.tab_widget.widget(tab) | |
287 |
km=tab.kernel_ |
|
287 | km=tab.kernel_client | |
288 |
|
288 | |||
289 | #build list of all widgets |
|
289 | #build list of all widgets | |
290 | widget_list = [self.tab_widget.widget(i) for i in range(self.tab_widget.count())] |
|
290 | widget_list = [self.tab_widget.widget(i) for i in range(self.tab_widget.count())] | |
@@ -292,7 +292,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
292 | # widget that are candidate to be the owner of the kernel does have all the same port of the curent widget |
|
292 | # widget that are candidate to be the owner of the kernel does have all the same port of the curent widget | |
293 | # And should have a _may_close attribute |
|
293 | # And should have a _may_close attribute | |
294 | filtered_widget_list = [ widget for widget in widget_list if |
|
294 | filtered_widget_list = [ widget for widget in widget_list if | |
295 |
widget.kernel_ |
|
295 | widget.kernel_client.connection_file == km.connection_file and | |
296 | hasattr(widget,'_may_close') ] |
|
296 | hasattr(widget,'_may_close') ] | |
297 | # the master widget is the one that may close the kernel |
|
297 | # the master widget is the one that may close the kernel | |
298 | master_widget= [ widget for widget in filtered_widget_list if widget._may_close] |
|
298 | master_widget= [ widget for widget in filtered_widget_list if widget._may_close] | |
@@ -315,14 +315,14 b' class MainWindow(QtGui.QMainWindow):' | |||||
315 | #convert from/to int/richIpythonWidget if needed |
|
315 | #convert from/to int/richIpythonWidget if needed | |
316 | if isinstance(tab, int): |
|
316 | if isinstance(tab, int): | |
317 | tab = self.tab_widget.widget(tab) |
|
317 | tab = self.tab_widget.widget(tab) | |
318 |
km=tab.kernel_ |
|
318 | km=tab.kernel_client | |
319 |
|
319 | |||
320 | #build list of all widgets |
|
320 | #build list of all widgets | |
321 | widget_list = [self.tab_widget.widget(i) for i in range(self.tab_widget.count())] |
|
321 | widget_list = [self.tab_widget.widget(i) for i in range(self.tab_widget.count())] | |
322 |
|
322 | |||
323 | # widget that are candidate not to be the owner of the kernel does have all the same port of the curent widget |
|
323 | # widget that are candidate not to be the owner of the kernel does have all the same port of the curent widget | |
324 | filtered_widget_list = ( widget for widget in widget_list if |
|
324 | filtered_widget_list = ( widget for widget in widget_list if | |
325 |
widget.kernel_ |
|
325 | widget.kernel_client.connection_file == km.connection_file) | |
326 | # Get a list of all widget owning the same kernel and removed it from |
|
326 | # Get a list of all widget owning the same kernel and removed it from | |
327 | # the previous cadidate. (better using sets ?) |
|
327 | # the previous cadidate. (better using sets ?) | |
328 | master_widget_list = self.find_master_tab(tab, as_list=True) |
|
328 | master_widget_list = self.find_master_tab(tab, as_list=True) |
@@ -64,7 +64,7 b' from IPython.frontend.qt.console.ipython_widget import IPythonWidget' | |||||
64 | from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget |
|
64 | from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget | |
65 | from IPython.frontend.qt.console import styles |
|
65 | from IPython.frontend.qt.console import styles | |
66 | from IPython.frontend.qt.console.mainwindow import MainWindow |
|
66 | from IPython.frontend.qt.console.mainwindow import MainWindow | |
67 |
from IPython.frontend.qt. |
|
67 | from IPython.frontend.qt.client import QtKernelClient | |
68 | from IPython.kernel import tunnel_to_kernel, find_connection_file |
|
68 | from IPython.kernel import tunnel_to_kernel, find_connection_file | |
69 | from IPython.utils.path import filefind |
|
69 | from IPython.utils.path import filefind | |
70 | from IPython.utils.py3compat import str_to_bytes |
|
70 | from IPython.utils.py3compat import str_to_bytes | |
@@ -166,7 +166,7 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
166 | aliases = Dict(aliases) |
|
166 | aliases = Dict(aliases) | |
167 | frontend_flags = Any(qt_flags) |
|
167 | frontend_flags = Any(qt_flags) | |
168 | frontend_aliases = Any(qt_aliases) |
|
168 | frontend_aliases = Any(qt_aliases) | |
169 |
kernel_ |
|
169 | kernel_client_class = QtKernelClient | |
170 |
|
170 | |||
171 | stylesheet = Unicode('', config=True, |
|
171 | stylesheet = Unicode('', config=True, | |
172 | help="path to a custom CSS stylesheet") |
|
172 | help="path to a custom CSS stylesheet") | |
@@ -201,7 +201,7 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
201 | kwargs = dict() |
|
201 | kwargs = dict() | |
202 | kwargs['extra_arguments'] = self.kernel_argv |
|
202 | kwargs['extra_arguments'] = self.kernel_argv | |
203 | kernel_manager.start_kernel(**kwargs) |
|
203 | kernel_manager.start_kernel(**kwargs) | |
204 |
kernel_ |
|
204 | kernel_client.start_channels() | |
205 | widget = self.widget_factory(config=self.config, |
|
205 | widget = self.widget_factory(config=self.config, | |
206 | local_kernel=True) |
|
206 | local_kernel=True) | |
207 | self.init_colors(widget) |
|
207 | self.init_colors(widget) | |
@@ -219,19 +219,19 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
219 | current_widget : IPythonWidget |
|
219 | current_widget : IPythonWidget | |
220 | The IPythonWidget whose kernel this frontend is to share |
|
220 | The IPythonWidget whose kernel this frontend is to share | |
221 | """ |
|
221 | """ | |
222 |
kernel_ |
|
222 | kernel_client = self.kernel_client_class( | |
223 |
connection_file=current_widget.kernel_ |
|
223 | connection_file=current_widget.kernel_client.connection_file, | |
224 | config = self.config, |
|
224 | config = self.config, | |
225 | ) |
|
225 | ) | |
226 |
kernel_ |
|
226 | kernel_client.load_connection_file() | |
227 |
kernel_ |
|
227 | kernel_client.start_channels() | |
228 | widget = self.widget_factory(config=self.config, |
|
228 | widget = self.widget_factory(config=self.config, | |
229 | local_kernel=False) |
|
229 | local_kernel=False) | |
230 | self.init_colors(widget) |
|
230 | self.init_colors(widget) | |
231 | widget._existing = True |
|
231 | widget._existing = True | |
232 | widget._may_close = False |
|
232 | widget._may_close = False | |
233 | widget._confirm_exit = False |
|
233 | widget._confirm_exit = False | |
234 |
widget.kernel_ |
|
234 | widget.kernel_client = kernel_client | |
235 | return widget |
|
235 | return widget | |
236 |
|
236 | |||
237 | def init_qt_elements(self): |
|
237 | def init_qt_elements(self): | |
@@ -256,6 +256,7 b' class IPythonQtConsoleApp(BaseIPythonApplication, IPythonConsoleApp):' | |||||
256 | self.widget._confirm_exit = self.confirm_exit |
|
256 | self.widget._confirm_exit = self.confirm_exit | |
257 |
|
257 | |||
258 | self.widget.kernel_manager = self.kernel_manager |
|
258 | self.widget.kernel_manager = self.kernel_manager | |
|
259 | self.widget.kernel_client = self.kernel_client | |||
259 | self.window = MainWindow(self.app, |
|
260 | self.window = MainWindow(self.app, | |
260 | confirm_exit=self.confirm_exit, |
|
261 | confirm_exit=self.confirm_exit, | |
261 | new_frontend_factory=self.new_frontend_master, |
|
262 | new_frontend_factory=self.new_frontend_master, |
@@ -54,20 +54,12 b' class QtShellChannelMixin(ChannelQObject):' | |||||
54 | # Emitted when any message is received. |
|
54 | # Emitted when any message is received. | |
55 | message_received = QtCore.Signal(object) |
|
55 | message_received = QtCore.Signal(object) | |
56 |
|
56 | |||
57 | # Emitted when a reply has been received for the corresponding request |
|
57 | # Emitted when a reply has been received for the corresponding request type. | |
58 | # type. |
|
|||
59 | execute_reply = QtCore.Signal(object) |
|
58 | execute_reply = QtCore.Signal(object) | |
60 | complete_reply = QtCore.Signal(object) |
|
59 | complete_reply = QtCore.Signal(object) | |
61 | object_info_reply = QtCore.Signal(object) |
|
60 | object_info_reply = QtCore.Signal(object) | |
62 | history_reply = QtCore.Signal(object) |
|
61 | history_reply = QtCore.Signal(object) | |
63 |
|
62 | |||
64 | # Emitted when the first reply comes back. |
|
|||
65 | first_reply = QtCore.Signal() |
|
|||
66 |
|
||||
67 | # Used by the first_reply signal logic to determine if a reply is the |
|
|||
68 | # first. |
|
|||
69 | _handlers_called = False |
|
|||
70 |
|
||||
71 | #--------------------------------------------------------------------------- |
|
63 | #--------------------------------------------------------------------------- | |
72 | # 'ShellChannel' interface |
|
64 | # 'ShellChannel' interface | |
73 | #--------------------------------------------------------------------------- |
|
65 | #--------------------------------------------------------------------------- | |
@@ -84,19 +76,6 b' class QtShellChannelMixin(ChannelQObject):' | |||||
84 | if signal: |
|
76 | if signal: | |
85 | signal.emit(msg) |
|
77 | signal.emit(msg) | |
86 |
|
78 | |||
87 | if not self._handlers_called: |
|
|||
88 | self.first_reply.emit() |
|
|||
89 | self._handlers_called = True |
|
|||
90 |
|
||||
91 | #--------------------------------------------------------------------------- |
|
|||
92 | # 'QtShellChannelMixin' interface |
|
|||
93 | #--------------------------------------------------------------------------- |
|
|||
94 |
|
||||
95 | def reset_first_reply(self): |
|
|||
96 | """ Reset the first_reply signal to fire again on the next reply. |
|
|||
97 | """ |
|
|||
98 | self._handlers_called = False |
|
|||
99 |
|
||||
100 |
|
79 | |||
101 | class QtIOPubChannelMixin(ChannelQObject): |
|
80 | class QtIOPubChannelMixin(ChannelQObject): | |
102 |
|
81 | |||
@@ -189,19 +168,16 b' class QtHBChannelMixin(ChannelQObject):' | |||||
189 | self.kernel_died.emit(since_last_heartbeat) |
|
168 | self.kernel_died.emit(since_last_heartbeat) | |
190 |
|
169 | |||
191 |
|
170 | |||
192 |
class QtKernel |
|
171 | class QtKernelClientMixin(HasTraits, SuperQObject): | |
193 |
""" A Kernel |
|
172 | """ A KernelClient that provides signals and slots. | |
194 | """ |
|
173 | """ | |
195 |
|
174 | |||
196 | __metaclass__ = MetaQObjectHasTraits |
|
175 | __metaclass__ = MetaQObjectHasTraits | |
197 |
|
176 | |||
198 |
# Emitted when the kernel |
|
177 | # Emitted when the kernel client has started listening. | |
199 | started_kernel = QtCore.Signal() |
|
|||
200 |
|
||||
201 | # Emitted when the kernel manager has started listening. |
|
|||
202 | started_channels = QtCore.Signal() |
|
178 | started_channels = QtCore.Signal() | |
203 |
|
179 | |||
204 |
# Emitted when the kernel |
|
180 | # Emitted when the kernel client has stopped listening. | |
205 | stopped_channels = QtCore.Signal() |
|
181 | stopped_channels = QtCore.Signal() | |
206 |
|
182 | |||
207 | # Use Qt-specific channel classes that emit signals. |
|
183 | # Use Qt-specific channel classes that emit signals. | |
@@ -211,50 +187,19 b' class QtKernelManagerMixin(HasTraits, SuperQObject):' | |||||
211 | hb_channel_class = Type(QtHBChannelMixin) |
|
187 | hb_channel_class = Type(QtHBChannelMixin) | |
212 |
|
188 | |||
213 | #--------------------------------------------------------------------------- |
|
189 | #--------------------------------------------------------------------------- | |
214 |
# 'Kernel |
|
190 | # 'KernelClient' interface | |
215 | #--------------------------------------------------------------------------- |
|
191 | #--------------------------------------------------------------------------- | |
216 |
|
192 | |||
217 | #------ Kernel process management ------------------------------------------ |
|
|||
218 |
|
||||
219 | def start_kernel(self, *args, **kw): |
|
|||
220 | """ Reimplemented for proper heartbeat management. |
|
|||
221 | """ |
|
|||
222 | if self._shell_channel is not None: |
|
|||
223 | self._shell_channel.reset_first_reply() |
|
|||
224 | super(QtKernelManagerMixin, self).start_kernel(*args, **kw) |
|
|||
225 | self.started_kernel.emit() |
|
|||
226 |
|
||||
227 | #------ Channel management ------------------------------------------------- |
|
193 | #------ Channel management ------------------------------------------------- | |
228 |
|
194 | |||
229 | def start_channels(self, *args, **kw): |
|
195 | def start_channels(self, *args, **kw): | |
230 | """ Reimplemented to emit signal. |
|
196 | """ Reimplemented to emit signal. | |
231 | """ |
|
197 | """ | |
232 |
super(QtKernel |
|
198 | super(QtKernelClientMixin, self).start_channels(*args, **kw) | |
233 | self.started_channels.emit() |
|
199 | self.started_channels.emit() | |
234 |
|
200 | |||
235 | def stop_channels(self): |
|
201 | def stop_channels(self): | |
236 | """ Reimplemented to emit signal. |
|
202 | """ Reimplemented to emit signal. | |
237 | """ |
|
203 | """ | |
238 |
super(QtKernel |
|
204 | super(QtKernelClientMixin, self).stop_channels() | |
239 | self.stopped_channels.emit() |
|
205 | self.stopped_channels.emit() | |
240 |
|
||||
241 | @property |
|
|||
242 | def shell_channel(self): |
|
|||
243 | """ Reimplemented for proper heartbeat management. |
|
|||
244 | """ |
|
|||
245 | if self._shell_channel is None: |
|
|||
246 | self._shell_channel = super(QtKernelManagerMixin,self).shell_channel |
|
|||
247 | self._shell_channel.first_reply.connect(self._first_reply) |
|
|||
248 | return self._shell_channel |
|
|||
249 |
|
||||
250 | #--------------------------------------------------------------------------- |
|
|||
251 | # Protected interface |
|
|||
252 | #--------------------------------------------------------------------------- |
|
|||
253 |
|
||||
254 | def _first_reply(self): |
|
|||
255 | """ Unpauses the heartbeat channel when the first reply is received on |
|
|||
256 | the execute channel. Note that this will *not* start the heartbeat |
|
|||
257 | channel if it is not already running! |
|
|||
258 | """ |
|
|||
259 | if self._hb_channel is not None: |
|
|||
260 | self._hb_channel.unpause() |
|
General Comments 0
You need to be logged in to leave comments.
Login now