@@ -35,12 +35,13 @@ def validate_string_dict(dct):
35
35
class KernelClient (ConnectionFileMixin ):
36
36
"""Communicates with a single kernel on any host via zmq channels.
37
37
38
- There are four channels associated with each kernel:
38
+ There are five channels associated with each kernel:
39
39
40
40
* shell: for request/reply calls to the kernel.
41
41
* iopub: for the kernel to publish results to frontends.
42
42
* hb: for monitoring the kernel's heartbeat.
43
43
* stdin: for frontends to reply to raw_input calls in the kernel.
44
+ * control: for kernel management calls to the kernel.
44
45
45
46
The messages that can be sent on these channels are exposed as methods of the
46
47
client (KernelClient.execute, complete, history, etc.). These methods only
@@ -58,12 +59,14 @@ def _context_default(self):
58
59
iopub_channel_class = Type (ChannelABC )
59
60
stdin_channel_class = Type (ChannelABC )
60
61
hb_channel_class = Type (HBChannelABC )
62
+ control_channel_class = Type (ChannelABC )
61
63
62
64
# Protected traits
63
65
_shell_channel = Any ()
64
66
_iopub_channel = Any ()
65
67
_stdin_channel = Any ()
66
68
_hb_channel = Any ()
69
+ _control_channel = Any ()
67
70
68
71
# flag for whether execute requests should be allowed to call raw_input:
69
72
allow_stdin = True
@@ -84,11 +87,15 @@ def get_stdin_msg(self, *args, **kwargs):
84
87
"""Get a message from the stdin channel"""
85
88
return self .stdin_channel .get_msg (* args , ** kwargs )
86
89
90
+ def get_control_msg (self , * args , ** kwargs ):
91
+ """Get a message from the control channel"""
92
+ return self .control_channel .get_msg (* args , ** kwargs )
93
+
87
94
#--------------------------------------------------------------------------
88
95
# Channel management methods
89
96
#--------------------------------------------------------------------------
90
97
91
- def start_channels (self , shell = True , iopub = True , stdin = True , hb = True ):
98
+ def start_channels (self , shell = True , iopub = True , stdin = True , hb = True , control = True ):
92
99
"""Starts the channels for this kernel.
93
100
94
101
This will create the channels if they do not exist and then start
@@ -109,6 +116,8 @@ def start_channels(self, shell=True, iopub=True, stdin=True, hb=True):
109
116
self .allow_stdin = False
110
117
if hb :
111
118
self .hb_channel .start ()
119
+ if control :
120
+ self .control_channel .start ()
112
121
113
122
def stop_channels (self ):
114
123
"""Stops all the running channels for this kernel.
@@ -123,12 +132,15 @@ def stop_channels(self):
123
132
self .stdin_channel .stop ()
124
133
if self .hb_channel .is_alive ():
125
134
self .hb_channel .stop ()
135
+ if self .control_channel .is_alive ():
136
+ self .control_channel .stop ()
126
137
127
138
@property
128
139
def channels_running (self ):
129
140
"""Are any of the channels created and running?"""
130
141
return (self .shell_channel .is_alive () or self .iopub_channel .is_alive () or
131
- self .stdin_channel .is_alive () or self .hb_channel .is_alive ())
142
+ self .stdin_channel .is_alive () or self .hb_channel .is_alive () or
143
+ self .control_channel .is_alive ())
132
144
133
145
ioloop = None # Overridden in subclasses that use pyzmq event loop
134
146
@@ -179,6 +191,18 @@ def hb_channel(self):
179
191
)
180
192
return self ._hb_channel
181
193
194
+ @property
195
+ def control_channel (self ):
196
+ """Get the control channel object for this kernel."""
197
+ if self ._control_channel is None :
198
+ url = self ._make_url ('control' )
199
+ self .log .debug ("connecting control channel to %s" , url )
200
+ socket = self .connect_control (identity = self .session .bsession )
201
+ self ._control_channel = self .control_channel_class (
202
+ socket , self .session , self .ioloop
203
+ )
204
+ return self ._control_channel
205
+
182
206
def is_alive (self ):
183
207
"""Is the kernel process still running?"""
184
208
from .manager import KernelManager
@@ -383,8 +407,24 @@ def _handle_kernel_info_reply(self, msg):
383
407
if adapt_version != major_protocol_version :
384
408
self .session .adapt_version = adapt_version
385
409
410
+ def is_complete (self , code ):
411
+ """Ask the kernel whether some code is complete and ready to execute."""
412
+ msg = self .session .msg ('is_complete_request' , {'code' : code })
413
+ self .shell_channel .send (msg )
414
+ return msg ['header' ]['msg_id' ]
415
+
416
+ def input (self , string ):
417
+ """Send a string of raw input to the kernel.
418
+
419
+ This should only be called in response to the kernel sending an
420
+ ``input_request`` message on the stdin channel.
421
+ """
422
+ content = dict (value = string )
423
+ msg = self .session .msg ('input_reply' , content )
424
+ self .stdin_channel .send (msg )
425
+
386
426
def shutdown (self , restart = False ):
387
- """Request an immediate kernel shutdown.
427
+ """Request an immediate kernel shutdown on the control channel .
388
428
389
429
Upon receipt of the (empty) reply, client code can safely assume that
390
430
the kernel has shut down and it's safe to forcefully terminate it if
@@ -401,24 +441,7 @@ def shutdown(self, restart=False):
401
441
# Send quit message to kernel. Once we implement kernel-side setattr,
402
442
# this should probably be done that way, but for now this will do.
403
443
msg = self .session .msg ('shutdown_request' , {'restart' :restart })
404
- self .shell_channel .send (msg )
405
- return msg ['header' ]['msg_id' ]
406
-
407
- def is_complete (self , code ):
408
- """Ask the kernel whether some code is complete and ready to execute."""
409
- msg = self .session .msg ('is_complete_request' , {'code' : code })
410
- self .shell_channel .send (msg )
444
+ self .control_channel .send (msg )
411
445
return msg ['header' ]['msg_id' ]
412
446
413
- def input (self , string ):
414
- """Send a string of raw input to the kernel.
415
-
416
- This should only be called in response to the kernel sending an
417
- ``input_request`` message on the stdin channel.
418
- """
419
- content = dict (value = string )
420
- msg = self .session .msg ('input_reply' , content )
421
- self .stdin_channel .send (msg )
422
-
423
-
424
447
KernelClientABC .register (KernelClient )
0 commit comments