|
@@
-1,789
+1,795
b''
|
|
1
|
#!/usr/bin/env python
|
|
1
|
#!/usr/bin/env python
|
|
2
|
"""An interactive kernel that talks to frontends over 0MQ."""
|
|
2
|
"""An interactive kernel that talks to frontends over 0MQ."""
|
|
3
|
|
|
3
|
|
|
4
|
#-----------------------------------------------------------------------------
|
|
4
|
#-----------------------------------------------------------------------------
|
|
5
|
# Imports
|
|
5
|
# Imports
|
|
6
|
#-----------------------------------------------------------------------------
|
|
6
|
#-----------------------------------------------------------------------------
|
|
7
|
from __future__ import print_function
|
|
7
|
from __future__ import print_function
|
|
8
|
|
|
8
|
|
|
9
|
# Standard library imports
|
|
9
|
# Standard library imports
|
|
10
|
import sys
|
|
10
|
import sys
|
|
11
|
import time
|
|
11
|
import time
|
|
12
|
import traceback
|
|
12
|
import traceback
|
|
13
|
import logging
|
|
13
|
import logging
|
|
14
|
import uuid
|
|
14
|
import uuid
|
|
15
|
|
|
15
|
|
|
16
|
from datetime import datetime
|
|
16
|
from datetime import datetime
|
|
17
|
from signal import (
|
|
17
|
from signal import (
|
|
18
|
signal, default_int_handler, SIGINT
|
|
18
|
signal, default_int_handler, SIGINT
|
|
19
|
)
|
|
19
|
)
|
|
20
|
|
|
20
|
|
|
21
|
# System library imports
|
|
21
|
# System library imports
|
|
22
|
import zmq
|
|
22
|
import zmq
|
|
23
|
from zmq.eventloop import ioloop
|
|
23
|
from zmq.eventloop import ioloop
|
|
24
|
from zmq.eventloop.zmqstream import ZMQStream
|
|
24
|
from zmq.eventloop.zmqstream import ZMQStream
|
|
25
|
|
|
25
|
|
|
26
|
# Local imports
|
|
26
|
# Local imports
|
|
27
|
from IPython.config.configurable import Configurable
|
|
27
|
from IPython.config.configurable import Configurable
|
|
28
|
from IPython.core.error import StdinNotImplementedError
|
|
28
|
from IPython.core.error import StdinNotImplementedError
|
|
29
|
from IPython.core import release
|
|
29
|
from IPython.core import release
|
|
30
|
from IPython.utils import py3compat
|
|
30
|
from IPython.utils import py3compat
|
|
31
|
from IPython.utils.py3compat import builtin_mod, unicode_type, string_types
|
|
31
|
from IPython.utils.py3compat import builtin_mod, unicode_type, string_types
|
|
32
|
from IPython.utils.jsonutil import json_clean
|
|
32
|
from IPython.utils.jsonutil import json_clean
|
|
33
|
from IPython.utils.traitlets import (
|
|
33
|
from IPython.utils.traitlets import (
|
|
34
|
Any, Instance, Float, Dict, List, Set, Integer, Unicode,
|
|
34
|
Any, Instance, Float, Dict, List, Set, Integer, Unicode,
|
|
35
|
Type
|
|
35
|
Type, Bool,
|
|
36
|
)
|
|
36
|
)
|
|
37
|
|
|
37
|
|
|
38
|
from .serialize import serialize_object, unpack_apply_message
|
|
38
|
from .serialize import serialize_object, unpack_apply_message
|
|
39
|
from .session import Session
|
|
39
|
from .session import Session
|
|
40
|
from .zmqshell import ZMQInteractiveShell
|
|
40
|
from .zmqshell import ZMQInteractiveShell
|
|
41
|
|
|
41
|
|
|
42
|
|
|
42
|
|
|
43
|
#-----------------------------------------------------------------------------
|
|
43
|
#-----------------------------------------------------------------------------
|
|
44
|
# Main kernel class
|
|
44
|
# Main kernel class
|
|
45
|
#-----------------------------------------------------------------------------
|
|
45
|
#-----------------------------------------------------------------------------
|
|
46
|
|
|
46
|
|
|
47
|
protocol_version = list(release.kernel_protocol_version_info)
|
|
47
|
protocol_version = list(release.kernel_protocol_version_info)
|
|
48
|
ipython_version = list(release.version_info)
|
|
48
|
ipython_version = list(release.version_info)
|
|
49
|
language_version = list(sys.version_info[:3])
|
|
49
|
language_version = list(sys.version_info[:3])
|
|
50
|
|
|
50
|
|
|
51
|
|
|
51
|
|
|
52
|
class Kernel(Configurable):
|
|
52
|
class Kernel(Configurable):
|
|
53
|
|
|
53
|
|
|
54
|
#---------------------------------------------------------------------------
|
|
54
|
#---------------------------------------------------------------------------
|
|
55
|
# Kernel interface
|
|
55
|
# Kernel interface
|
|
56
|
#---------------------------------------------------------------------------
|
|
56
|
#---------------------------------------------------------------------------
|
|
57
|
|
|
57
|
|
|
58
|
# attribute to override with a GUI
|
|
58
|
# attribute to override with a GUI
|
|
59
|
eventloop = Any(None)
|
|
59
|
eventloop = Any(None)
|
|
60
|
def _eventloop_changed(self, name, old, new):
|
|
60
|
def _eventloop_changed(self, name, old, new):
|
|
61
|
"""schedule call to eventloop from IOLoop"""
|
|
61
|
"""schedule call to eventloop from IOLoop"""
|
|
62
|
loop = ioloop.IOLoop.instance()
|
|
62
|
loop = ioloop.IOLoop.instance()
|
|
63
|
loop.add_timeout(time.time()+0.1, self.enter_eventloop)
|
|
63
|
loop.add_timeout(time.time()+0.1, self.enter_eventloop)
|
|
64
|
|
|
64
|
|
|
65
|
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
|
|
65
|
shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
|
|
66
|
shell_class = Type(ZMQInteractiveShell)
|
|
66
|
shell_class = Type(ZMQInteractiveShell)
|
|
67
|
|
|
67
|
|
|
68
|
session = Instance(Session)
|
|
68
|
session = Instance(Session)
|
|
69
|
profile_dir = Instance('IPython.core.profiledir.ProfileDir')
|
|
69
|
profile_dir = Instance('IPython.core.profiledir.ProfileDir')
|
|
70
|
shell_streams = List()
|
|
70
|
shell_streams = List()
|
|
71
|
control_stream = Instance(ZMQStream)
|
|
71
|
control_stream = Instance(ZMQStream)
|
|
72
|
iopub_socket = Instance(zmq.Socket)
|
|
72
|
iopub_socket = Instance(zmq.Socket)
|
|
73
|
stdin_socket = Instance(zmq.Socket)
|
|
73
|
stdin_socket = Instance(zmq.Socket)
|
|
74
|
log = Instance(logging.Logger)
|
|
74
|
log = Instance(logging.Logger)
|
|
75
|
|
|
75
|
|
|
76
|
user_module = Any()
|
|
76
|
user_module = Any()
|
|
77
|
def _user_module_changed(self, name, old, new):
|
|
77
|
def _user_module_changed(self, name, old, new):
|
|
78
|
if self.shell is not None:
|
|
78
|
if self.shell is not None:
|
|
79
|
self.shell.user_module = new
|
|
79
|
self.shell.user_module = new
|
|
80
|
|
|
80
|
|
|
81
|
user_ns = Instance(dict, args=None, allow_none=True)
|
|
81
|
user_ns = Instance(dict, args=None, allow_none=True)
|
|
82
|
def _user_ns_changed(self, name, old, new):
|
|
82
|
def _user_ns_changed(self, name, old, new):
|
|
83
|
if self.shell is not None:
|
|
83
|
if self.shell is not None:
|
|
84
|
self.shell.user_ns = new
|
|
84
|
self.shell.user_ns = new
|
|
85
|
self.shell.init_user_ns()
|
|
85
|
self.shell.init_user_ns()
|
|
86
|
|
|
86
|
|
|
87
|
# identities:
|
|
87
|
# identities:
|
|
88
|
int_id = Integer(-1)
|
|
88
|
int_id = Integer(-1)
|
|
89
|
ident = Unicode()
|
|
89
|
ident = Unicode()
|
|
90
|
|
|
90
|
|
|
91
|
def _ident_default(self):
|
|
91
|
def _ident_default(self):
|
|
92
|
return unicode_type(uuid.uuid4())
|
|
92
|
return unicode_type(uuid.uuid4())
|
|
93
|
|
|
93
|
|
|
94
|
|
|
|
|
|
95
|
# Private interface
|
|
94
|
# Private interface
|
|
96
|
|
|
95
|
|
|
|
|
|
96
|
_darwin_app_nap = Bool(True, config=True,
|
|
|
|
|
97
|
help="""Whether to use appnope for compatiblity with OS X App Nap.
|
|
|
|
|
98
|
|
|
|
|
|
99
|
Only affects OS X >= 10.9.
|
|
|
|
|
100
|
"""
|
|
|
|
|
101
|
)
|
|
|
|
|
102
|
|
|
97
|
# Time to sleep after flushing the stdout/err buffers in each execute
|
|
103
|
# Time to sleep after flushing the stdout/err buffers in each execute
|
|
98
|
# cycle. While this introduces a hard limit on the minimal latency of the
|
|
104
|
# cycle. While this introduces a hard limit on the minimal latency of the
|
|
99
|
# execute cycle, it helps prevent output synchronization problems for
|
|
105
|
# execute cycle, it helps prevent output synchronization problems for
|
|
100
|
# clients.
|
|
106
|
# clients.
|
|
101
|
# Units are in seconds. The minimum zmq latency on local host is probably
|
|
107
|
# Units are in seconds. The minimum zmq latency on local host is probably
|
|
102
|
# ~150 microseconds, set this to 500us for now. We may need to increase it
|
|
108
|
# ~150 microseconds, set this to 500us for now. We may need to increase it
|
|
103
|
# a little if it's not enough after more interactive testing.
|
|
109
|
# a little if it's not enough after more interactive testing.
|
|
104
|
_execute_sleep = Float(0.0005, config=True)
|
|
110
|
_execute_sleep = Float(0.0005, config=True)
|
|
105
|
|
|
111
|
|
|
106
|
# Frequency of the kernel's event loop.
|
|
112
|
# Frequency of the kernel's event loop.
|
|
107
|
# Units are in seconds, kernel subclasses for GUI toolkits may need to
|
|
113
|
# Units are in seconds, kernel subclasses for GUI toolkits may need to
|
|
108
|
# adapt to milliseconds.
|
|
114
|
# adapt to milliseconds.
|
|
109
|
_poll_interval = Float(0.05, config=True)
|
|
115
|
_poll_interval = Float(0.05, config=True)
|
|
110
|
|
|
116
|
|
|
111
|
# If the shutdown was requested over the network, we leave here the
|
|
117
|
# If the shutdown was requested over the network, we leave here the
|
|
112
|
# necessary reply message so it can be sent by our registered atexit
|
|
118
|
# necessary reply message so it can be sent by our registered atexit
|
|
113
|
# handler. This ensures that the reply is only sent to clients truly at
|
|
119
|
# handler. This ensures that the reply is only sent to clients truly at
|
|
114
|
# the end of our shutdown process (which happens after the underlying
|
|
120
|
# the end of our shutdown process (which happens after the underlying
|
|
115
|
# IPython shell's own shutdown).
|
|
121
|
# IPython shell's own shutdown).
|
|
116
|
_shutdown_message = None
|
|
122
|
_shutdown_message = None
|
|
117
|
|
|
123
|
|
|
118
|
# This is a dict of port number that the kernel is listening on. It is set
|
|
124
|
# This is a dict of port number that the kernel is listening on. It is set
|
|
119
|
# by record_ports and used by connect_request.
|
|
125
|
# by record_ports and used by connect_request.
|
|
120
|
_recorded_ports = Dict()
|
|
126
|
_recorded_ports = Dict()
|
|
121
|
|
|
127
|
|
|
122
|
# A reference to the Python builtin 'raw_input' function.
|
|
128
|
# A reference to the Python builtin 'raw_input' function.
|
|
123
|
# (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
|
|
129
|
# (i.e., __builtin__.raw_input for Python 2.7, builtins.input for Python 3)
|
|
124
|
_sys_raw_input = Any()
|
|
130
|
_sys_raw_input = Any()
|
|
125
|
_sys_eval_input = Any()
|
|
131
|
_sys_eval_input = Any()
|
|
126
|
|
|
132
|
|
|
127
|
# set of aborted msg_ids
|
|
133
|
# set of aborted msg_ids
|
|
128
|
aborted = Set()
|
|
134
|
aborted = Set()
|
|
129
|
|
|
135
|
|
|
130
|
|
|
136
|
|
|
131
|
def __init__(self, **kwargs):
|
|
137
|
def __init__(self, **kwargs):
|
|
132
|
super(Kernel, self).__init__(**kwargs)
|
|
138
|
super(Kernel, self).__init__(**kwargs)
|
|
133
|
|
|
139
|
|
|
134
|
# Initialize the InteractiveShell subclass
|
|
140
|
# Initialize the InteractiveShell subclass
|
|
135
|
self.shell = self.shell_class.instance(parent=self,
|
|
141
|
self.shell = self.shell_class.instance(parent=self,
|
|
136
|
profile_dir = self.profile_dir,
|
|
142
|
profile_dir = self.profile_dir,
|
|
137
|
user_module = self.user_module,
|
|
143
|
user_module = self.user_module,
|
|
138
|
user_ns = self.user_ns,
|
|
144
|
user_ns = self.user_ns,
|
|
139
|
kernel = self,
|
|
145
|
kernel = self,
|
|
140
|
)
|
|
146
|
)
|
|
141
|
self.shell.displayhook.session = self.session
|
|
147
|
self.shell.displayhook.session = self.session
|
|
142
|
self.shell.displayhook.pub_socket = self.iopub_socket
|
|
148
|
self.shell.displayhook.pub_socket = self.iopub_socket
|
|
143
|
self.shell.displayhook.topic = self._topic('pyout')
|
|
149
|
self.shell.displayhook.topic = self._topic('pyout')
|
|
144
|
self.shell.display_pub.session = self.session
|
|
150
|
self.shell.display_pub.session = self.session
|
|
145
|
self.shell.display_pub.pub_socket = self.iopub_socket
|
|
151
|
self.shell.display_pub.pub_socket = self.iopub_socket
|
|
146
|
self.shell.data_pub.session = self.session
|
|
152
|
self.shell.data_pub.session = self.session
|
|
147
|
self.shell.data_pub.pub_socket = self.iopub_socket
|
|
153
|
self.shell.data_pub.pub_socket = self.iopub_socket
|
|
148
|
|
|
154
|
|
|
149
|
# TMP - hack while developing
|
|
155
|
# TMP - hack while developing
|
|
150
|
self.shell._reply_content = None
|
|
156
|
self.shell._reply_content = None
|
|
151
|
|
|
157
|
|
|
152
|
# Build dict of handlers for message types
|
|
158
|
# Build dict of handlers for message types
|
|
153
|
msg_types = [ 'execute_request', 'complete_request',
|
|
159
|
msg_types = [ 'execute_request', 'complete_request',
|
|
154
|
'object_info_request', 'history_request',
|
|
160
|
'object_info_request', 'history_request',
|
|
155
|
'kernel_info_request',
|
|
161
|
'kernel_info_request',
|
|
156
|
'connect_request', 'shutdown_request',
|
|
162
|
'connect_request', 'shutdown_request',
|
|
157
|
'apply_request',
|
|
163
|
'apply_request',
|
|
158
|
]
|
|
164
|
]
|
|
159
|
self.shell_handlers = {}
|
|
165
|
self.shell_handlers = {}
|
|
160
|
for msg_type in msg_types:
|
|
166
|
for msg_type in msg_types:
|
|
161
|
self.shell_handlers[msg_type] = getattr(self, msg_type)
|
|
167
|
self.shell_handlers[msg_type] = getattr(self, msg_type)
|
|
162
|
|
|
168
|
|
|
163
|
comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
|
|
169
|
comm_msg_types = [ 'comm_open', 'comm_msg', 'comm_close' ]
|
|
164
|
comm_manager = self.shell.comm_manager
|
|
170
|
comm_manager = self.shell.comm_manager
|
|
165
|
for msg_type in comm_msg_types:
|
|
171
|
for msg_type in comm_msg_types:
|
|
166
|
self.shell_handlers[msg_type] = getattr(comm_manager, msg_type)
|
|
172
|
self.shell_handlers[msg_type] = getattr(comm_manager, msg_type)
|
|
167
|
|
|
173
|
|
|
168
|
control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
|
|
174
|
control_msg_types = msg_types + [ 'clear_request', 'abort_request' ]
|
|
169
|
self.control_handlers = {}
|
|
175
|
self.control_handlers = {}
|
|
170
|
for msg_type in control_msg_types:
|
|
176
|
for msg_type in control_msg_types:
|
|
171
|
self.control_handlers[msg_type] = getattr(self, msg_type)
|
|
177
|
self.control_handlers[msg_type] = getattr(self, msg_type)
|
|
172
|
|
|
178
|
|
|
173
|
|
|
179
|
|
|
174
|
def dispatch_control(self, msg):
|
|
180
|
def dispatch_control(self, msg):
|
|
175
|
"""dispatch control requests"""
|
|
181
|
"""dispatch control requests"""
|
|
176
|
idents,msg = self.session.feed_identities(msg, copy=False)
|
|
182
|
idents,msg = self.session.feed_identities(msg, copy=False)
|
|
177
|
try:
|
|
183
|
try:
|
|
178
|
msg = self.session.unserialize(msg, content=True, copy=False)
|
|
184
|
msg = self.session.unserialize(msg, content=True, copy=False)
|
|
179
|
except:
|
|
185
|
except:
|
|
180
|
self.log.error("Invalid Control Message", exc_info=True)
|
|
186
|
self.log.error("Invalid Control Message", exc_info=True)
|
|
181
|
return
|
|
187
|
return
|
|
182
|
|
|
188
|
|
|
183
|
self.log.debug("Control received: %s", msg)
|
|
189
|
self.log.debug("Control received: %s", msg)
|
|
184
|
|
|
190
|
|
|
185
|
header = msg['header']
|
|
191
|
header = msg['header']
|
|
186
|
msg_id = header['msg_id']
|
|
192
|
msg_id = header['msg_id']
|
|
187
|
msg_type = header['msg_type']
|
|
193
|
msg_type = header['msg_type']
|
|
188
|
|
|
194
|
|
|
189
|
handler = self.control_handlers.get(msg_type, None)
|
|
195
|
handler = self.control_handlers.get(msg_type, None)
|
|
190
|
if handler is None:
|
|
196
|
if handler is None:
|
|
191
|
self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
|
|
197
|
self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r", msg_type)
|
|
192
|
else:
|
|
198
|
else:
|
|
193
|
try:
|
|
199
|
try:
|
|
194
|
handler(self.control_stream, idents, msg)
|
|
200
|
handler(self.control_stream, idents, msg)
|
|
195
|
except Exception:
|
|
201
|
except Exception:
|
|
196
|
self.log.error("Exception in control handler:", exc_info=True)
|
|
202
|
self.log.error("Exception in control handler:", exc_info=True)
|
|
197
|
|
|
203
|
|
|
198
|
def dispatch_shell(self, stream, msg):
|
|
204
|
def dispatch_shell(self, stream, msg):
|
|
199
|
"""dispatch shell requests"""
|
|
205
|
"""dispatch shell requests"""
|
|
200
|
# flush control requests first
|
|
206
|
# flush control requests first
|
|
201
|
if self.control_stream:
|
|
207
|
if self.control_stream:
|
|
202
|
self.control_stream.flush()
|
|
208
|
self.control_stream.flush()
|
|
203
|
|
|
209
|
|
|
204
|
idents,msg = self.session.feed_identities(msg, copy=False)
|
|
210
|
idents,msg = self.session.feed_identities(msg, copy=False)
|
|
205
|
try:
|
|
211
|
try:
|
|
206
|
msg = self.session.unserialize(msg, content=True, copy=False)
|
|
212
|
msg = self.session.unserialize(msg, content=True, copy=False)
|
|
207
|
except:
|
|
213
|
except:
|
|
208
|
self.log.error("Invalid Message", exc_info=True)
|
|
214
|
self.log.error("Invalid Message", exc_info=True)
|
|
209
|
return
|
|
215
|
return
|
|
210
|
|
|
216
|
|
|
211
|
header = msg['header']
|
|
217
|
header = msg['header']
|
|
212
|
msg_id = header['msg_id']
|
|
218
|
msg_id = header['msg_id']
|
|
213
|
msg_type = msg['header']['msg_type']
|
|
219
|
msg_type = msg['header']['msg_type']
|
|
214
|
|
|
220
|
|
|
215
|
# Print some info about this message and leave a '--->' marker, so it's
|
|
221
|
# Print some info about this message and leave a '--->' marker, so it's
|
|
216
|
# easier to trace visually the message chain when debugging. Each
|
|
222
|
# easier to trace visually the message chain when debugging. Each
|
|
217
|
# handler prints its message at the end.
|
|
223
|
# handler prints its message at the end.
|
|
218
|
self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
|
|
224
|
self.log.debug('\n*** MESSAGE TYPE:%s***', msg_type)
|
|
219
|
self.log.debug(' Content: %s\n --->\n ', msg['content'])
|
|
225
|
self.log.debug(' Content: %s\n --->\n ', msg['content'])
|
|
220
|
|
|
226
|
|
|
221
|
if msg_id in self.aborted:
|
|
227
|
if msg_id in self.aborted:
|
|
222
|
self.aborted.remove(msg_id)
|
|
228
|
self.aborted.remove(msg_id)
|
|
223
|
# is it safe to assume a msg_id will not be resubmitted?
|
|
229
|
# is it safe to assume a msg_id will not be resubmitted?
|
|
224
|
reply_type = msg_type.split('_')[0] + '_reply'
|
|
230
|
reply_type = msg_type.split('_')[0] + '_reply'
|
|
225
|
status = {'status' : 'aborted'}
|
|
231
|
status = {'status' : 'aborted'}
|
|
226
|
md = {'engine' : self.ident}
|
|
232
|
md = {'engine' : self.ident}
|
|
227
|
md.update(status)
|
|
233
|
md.update(status)
|
|
228
|
reply_msg = self.session.send(stream, reply_type, metadata=md,
|
|
234
|
reply_msg = self.session.send(stream, reply_type, metadata=md,
|
|
229
|
content=status, parent=msg, ident=idents)
|
|
235
|
content=status, parent=msg, ident=idents)
|
|
230
|
return
|
|
236
|
return
|
|
231
|
|
|
237
|
|
|
232
|
handler = self.shell_handlers.get(msg_type, None)
|
|
238
|
handler = self.shell_handlers.get(msg_type, None)
|
|
233
|
if handler is None:
|
|
239
|
if handler is None:
|
|
234
|
self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
|
|
240
|
self.log.error("UNKNOWN MESSAGE TYPE: %r", msg_type)
|
|
235
|
else:
|
|
241
|
else:
|
|
236
|
# ensure default_int_handler during handler call
|
|
242
|
# ensure default_int_handler during handler call
|
|
237
|
sig = signal(SIGINT, default_int_handler)
|
|
243
|
sig = signal(SIGINT, default_int_handler)
|
|
238
|
try:
|
|
244
|
try:
|
|
239
|
handler(stream, idents, msg)
|
|
245
|
handler(stream, idents, msg)
|
|
240
|
except Exception:
|
|
246
|
except Exception:
|
|
241
|
self.log.error("Exception in message handler:", exc_info=True)
|
|
247
|
self.log.error("Exception in message handler:", exc_info=True)
|
|
242
|
finally:
|
|
248
|
finally:
|
|
243
|
signal(SIGINT, sig)
|
|
249
|
signal(SIGINT, sig)
|
|
244
|
|
|
250
|
|
|
245
|
def enter_eventloop(self):
|
|
251
|
def enter_eventloop(self):
|
|
246
|
"""enter eventloop"""
|
|
252
|
"""enter eventloop"""
|
|
247
|
self.log.info("entering eventloop")
|
|
253
|
self.log.info("entering eventloop")
|
|
248
|
# restore default_int_handler
|
|
254
|
# restore default_int_handler
|
|
249
|
signal(SIGINT, default_int_handler)
|
|
255
|
signal(SIGINT, default_int_handler)
|
|
250
|
while self.eventloop is not None:
|
|
256
|
while self.eventloop is not None:
|
|
251
|
try:
|
|
257
|
try:
|
|
252
|
self.eventloop(self)
|
|
258
|
self.eventloop(self)
|
|
253
|
except KeyboardInterrupt:
|
|
259
|
except KeyboardInterrupt:
|
|
254
|
# Ctrl-C shouldn't crash the kernel
|
|
260
|
# Ctrl-C shouldn't crash the kernel
|
|
255
|
self.log.error("KeyboardInterrupt caught in kernel")
|
|
261
|
self.log.error("KeyboardInterrupt caught in kernel")
|
|
256
|
continue
|
|
262
|
continue
|
|
257
|
else:
|
|
263
|
else:
|
|
258
|
# eventloop exited cleanly, this means we should stop (right?)
|
|
264
|
# eventloop exited cleanly, this means we should stop (right?)
|
|
259
|
self.eventloop = None
|
|
265
|
self.eventloop = None
|
|
260
|
break
|
|
266
|
break
|
|
261
|
self.log.info("exiting eventloop")
|
|
267
|
self.log.info("exiting eventloop")
|
|
262
|
|
|
268
|
|
|
263
|
def start(self):
|
|
269
|
def start(self):
|
|
264
|
"""register dispatchers for streams"""
|
|
270
|
"""register dispatchers for streams"""
|
|
265
|
self.shell.exit_now = False
|
|
271
|
self.shell.exit_now = False
|
|
266
|
if self.control_stream:
|
|
272
|
if self.control_stream:
|
|
267
|
self.control_stream.on_recv(self.dispatch_control, copy=False)
|
|
273
|
self.control_stream.on_recv(self.dispatch_control, copy=False)
|
|
268
|
|
|
274
|
|
|
269
|
def make_dispatcher(stream):
|
|
275
|
def make_dispatcher(stream):
|
|
270
|
def dispatcher(msg):
|
|
276
|
def dispatcher(msg):
|
|
271
|
return self.dispatch_shell(stream, msg)
|
|
277
|
return self.dispatch_shell(stream, msg)
|
|
272
|
return dispatcher
|
|
278
|
return dispatcher
|
|
273
|
|
|
279
|
|
|
274
|
for s in self.shell_streams:
|
|
280
|
for s in self.shell_streams:
|
|
275
|
s.on_recv(make_dispatcher(s), copy=False)
|
|
281
|
s.on_recv(make_dispatcher(s), copy=False)
|
|
276
|
|
|
282
|
|
|
277
|
# publish idle status
|
|
283
|
# publish idle status
|
|
278
|
self._publish_status('starting')
|
|
284
|
self._publish_status('starting')
|
|
279
|
|
|
285
|
|
|
280
|
def do_one_iteration(self):
|
|
286
|
def do_one_iteration(self):
|
|
281
|
"""step eventloop just once"""
|
|
287
|
"""step eventloop just once"""
|
|
282
|
if self.control_stream:
|
|
288
|
if self.control_stream:
|
|
283
|
self.control_stream.flush()
|
|
289
|
self.control_stream.flush()
|
|
284
|
for stream in self.shell_streams:
|
|
290
|
for stream in self.shell_streams:
|
|
285
|
# handle at most one request per iteration
|
|
291
|
# handle at most one request per iteration
|
|
286
|
stream.flush(zmq.POLLIN, 1)
|
|
292
|
stream.flush(zmq.POLLIN, 1)
|
|
287
|
stream.flush(zmq.POLLOUT)
|
|
293
|
stream.flush(zmq.POLLOUT)
|
|
288
|
|
|
294
|
|
|
289
|
|
|
295
|
|
|
290
|
def record_ports(self, ports):
|
|
296
|
def record_ports(self, ports):
|
|
291
|
"""Record the ports that this kernel is using.
|
|
297
|
"""Record the ports that this kernel is using.
|
|
292
|
|
|
298
|
|
|
293
|
The creator of the Kernel instance must call this methods if they
|
|
299
|
The creator of the Kernel instance must call this methods if they
|
|
294
|
want the :meth:`connect_request` method to return the port numbers.
|
|
300
|
want the :meth:`connect_request` method to return the port numbers.
|
|
295
|
"""
|
|
301
|
"""
|
|
296
|
self._recorded_ports = ports
|
|
302
|
self._recorded_ports = ports
|
|
297
|
|
|
303
|
|
|
298
|
#---------------------------------------------------------------------------
|
|
304
|
#---------------------------------------------------------------------------
|
|
299
|
# Kernel request handlers
|
|
305
|
# Kernel request handlers
|
|
300
|
#---------------------------------------------------------------------------
|
|
306
|
#---------------------------------------------------------------------------
|
|
301
|
|
|
307
|
|
|
302
|
def _make_metadata(self, other=None):
|
|
308
|
def _make_metadata(self, other=None):
|
|
303
|
"""init metadata dict, for execute/apply_reply"""
|
|
309
|
"""init metadata dict, for execute/apply_reply"""
|
|
304
|
new_md = {
|
|
310
|
new_md = {
|
|
305
|
'dependencies_met' : True,
|
|
311
|
'dependencies_met' : True,
|
|
306
|
'engine' : self.ident,
|
|
312
|
'engine' : self.ident,
|
|
307
|
'started': datetime.now(),
|
|
313
|
'started': datetime.now(),
|
|
308
|
}
|
|
314
|
}
|
|
309
|
if other:
|
|
315
|
if other:
|
|
310
|
new_md.update(other)
|
|
316
|
new_md.update(other)
|
|
311
|
return new_md
|
|
317
|
return new_md
|
|
312
|
|
|
318
|
|
|
313
|
def _publish_pyin(self, code, parent, execution_count):
|
|
319
|
def _publish_pyin(self, code, parent, execution_count):
|
|
314
|
"""Publish the code request on the pyin stream."""
|
|
320
|
"""Publish the code request on the pyin stream."""
|
|
315
|
|
|
321
|
|
|
316
|
self.session.send(self.iopub_socket, u'pyin',
|
|
322
|
self.session.send(self.iopub_socket, u'pyin',
|
|
317
|
{u'code':code, u'execution_count': execution_count},
|
|
323
|
{u'code':code, u'execution_count': execution_count},
|
|
318
|
parent=parent, ident=self._topic('pyin')
|
|
324
|
parent=parent, ident=self._topic('pyin')
|
|
319
|
)
|
|
325
|
)
|
|
320
|
|
|
326
|
|
|
321
|
def _publish_status(self, status, parent=None):
|
|
327
|
def _publish_status(self, status, parent=None):
|
|
322
|
"""send status (busy/idle) on IOPub"""
|
|
328
|
"""send status (busy/idle) on IOPub"""
|
|
323
|
self.session.send(self.iopub_socket,
|
|
329
|
self.session.send(self.iopub_socket,
|
|
324
|
u'status',
|
|
330
|
u'status',
|
|
325
|
{u'execution_state': status},
|
|
331
|
{u'execution_state': status},
|
|
326
|
parent=parent,
|
|
332
|
parent=parent,
|
|
327
|
ident=self._topic('status'),
|
|
333
|
ident=self._topic('status'),
|
|
328
|
)
|
|
334
|
)
|
|
329
|
|
|
335
|
|
|
330
|
|
|
336
|
|
|
331
|
def execute_request(self, stream, ident, parent):
|
|
337
|
def execute_request(self, stream, ident, parent):
|
|
332
|
"""handle an execute_request"""
|
|
338
|
"""handle an execute_request"""
|
|
333
|
|
|
339
|
|
|
334
|
self._publish_status(u'busy', parent)
|
|
340
|
self._publish_status(u'busy', parent)
|
|
335
|
|
|
341
|
|
|
336
|
try:
|
|
342
|
try:
|
|
337
|
content = parent[u'content']
|
|
343
|
content = parent[u'content']
|
|
338
|
code = content[u'code']
|
|
344
|
code = content[u'code']
|
|
339
|
silent = content[u'silent']
|
|
345
|
silent = content[u'silent']
|
|
340
|
store_history = content.get(u'store_history', not silent)
|
|
346
|
store_history = content.get(u'store_history', not silent)
|
|
341
|
except:
|
|
347
|
except:
|
|
342
|
self.log.error("Got bad msg: ")
|
|
348
|
self.log.error("Got bad msg: ")
|
|
343
|
self.log.error("%s", parent)
|
|
349
|
self.log.error("%s", parent)
|
|
344
|
return
|
|
350
|
return
|
|
345
|
|
|
351
|
|
|
346
|
md = self._make_metadata(parent['metadata'])
|
|
352
|
md = self._make_metadata(parent['metadata'])
|
|
347
|
|
|
353
|
|
|
348
|
shell = self.shell # we'll need this a lot here
|
|
354
|
shell = self.shell # we'll need this a lot here
|
|
349
|
|
|
355
|
|
|
350
|
# Replace raw_input. Note that is not sufficient to replace
|
|
356
|
# Replace raw_input. Note that is not sufficient to replace
|
|
351
|
# raw_input in the user namespace.
|
|
357
|
# raw_input in the user namespace.
|
|
352
|
if content.get('allow_stdin', False):
|
|
358
|
if content.get('allow_stdin', False):
|
|
353
|
raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
|
|
359
|
raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
|
|
354
|
input = lambda prompt='': eval(raw_input(prompt))
|
|
360
|
input = lambda prompt='': eval(raw_input(prompt))
|
|
355
|
else:
|
|
361
|
else:
|
|
356
|
raw_input = input = lambda prompt='' : self._no_raw_input()
|
|
362
|
raw_input = input = lambda prompt='' : self._no_raw_input()
|
|
357
|
|
|
363
|
|
|
358
|
if py3compat.PY3:
|
|
364
|
if py3compat.PY3:
|
|
359
|
self._sys_raw_input = builtin_mod.input
|
|
365
|
self._sys_raw_input = builtin_mod.input
|
|
360
|
builtin_mod.input = raw_input
|
|
366
|
builtin_mod.input = raw_input
|
|
361
|
else:
|
|
367
|
else:
|
|
362
|
self._sys_raw_input = builtin_mod.raw_input
|
|
368
|
self._sys_raw_input = builtin_mod.raw_input
|
|
363
|
self._sys_eval_input = builtin_mod.input
|
|
369
|
self._sys_eval_input = builtin_mod.input
|
|
364
|
builtin_mod.raw_input = raw_input
|
|
370
|
builtin_mod.raw_input = raw_input
|
|
365
|
builtin_mod.input = input
|
|
371
|
builtin_mod.input = input
|
|
366
|
|
|
372
|
|
|
367
|
# Set the parent message of the display hook and out streams.
|
|
373
|
# Set the parent message of the display hook and out streams.
|
|
368
|
shell.set_parent(parent)
|
|
374
|
shell.set_parent(parent)
|
|
369
|
|
|
375
|
|
|
370
|
# Re-broadcast our input for the benefit of listening clients, and
|
|
376
|
# Re-broadcast our input for the benefit of listening clients, and
|
|
371
|
# start computing output
|
|
377
|
# start computing output
|
|
372
|
if not silent:
|
|
378
|
if not silent:
|
|
373
|
self._publish_pyin(code, parent, shell.execution_count)
|
|
379
|
self._publish_pyin(code, parent, shell.execution_count)
|
|
374
|
|
|
380
|
|
|
375
|
reply_content = {}
|
|
381
|
reply_content = {}
|
|
376
|
try:
|
|
382
|
try:
|
|
377
|
# FIXME: the shell calls the exception handler itself.
|
|
383
|
# FIXME: the shell calls the exception handler itself.
|
|
378
|
shell.run_cell(code, store_history=store_history, silent=silent)
|
|
384
|
shell.run_cell(code, store_history=store_history, silent=silent)
|
|
379
|
except:
|
|
385
|
except:
|
|
380
|
status = u'error'
|
|
386
|
status = u'error'
|
|
381
|
# FIXME: this code right now isn't being used yet by default,
|
|
387
|
# FIXME: this code right now isn't being used yet by default,
|
|
382
|
# because the run_cell() call above directly fires off exception
|
|
388
|
# because the run_cell() call above directly fires off exception
|
|
383
|
# reporting. This code, therefore, is only active in the scenario
|
|
389
|
# reporting. This code, therefore, is only active in the scenario
|
|
384
|
# where runlines itself has an unhandled exception. We need to
|
|
390
|
# where runlines itself has an unhandled exception. We need to
|
|
385
|
# uniformize this, for all exception construction to come from a
|
|
391
|
# uniformize this, for all exception construction to come from a
|
|
386
|
# single location in the codbase.
|
|
392
|
# single location in the codbase.
|
|
387
|
etype, evalue, tb = sys.exc_info()
|
|
393
|
etype, evalue, tb = sys.exc_info()
|
|
388
|
tb_list = traceback.format_exception(etype, evalue, tb)
|
|
394
|
tb_list = traceback.format_exception(etype, evalue, tb)
|
|
389
|
reply_content.update(shell._showtraceback(etype, evalue, tb_list))
|
|
395
|
reply_content.update(shell._showtraceback(etype, evalue, tb_list))
|
|
390
|
else:
|
|
396
|
else:
|
|
391
|
status = u'ok'
|
|
397
|
status = u'ok'
|
|
392
|
finally:
|
|
398
|
finally:
|
|
393
|
# Restore raw_input.
|
|
399
|
# Restore raw_input.
|
|
394
|
if py3compat.PY3:
|
|
400
|
if py3compat.PY3:
|
|
395
|
builtin_mod.input = self._sys_raw_input
|
|
401
|
builtin_mod.input = self._sys_raw_input
|
|
396
|
else:
|
|
402
|
else:
|
|
397
|
builtin_mod.raw_input = self._sys_raw_input
|
|
403
|
builtin_mod.raw_input = self._sys_raw_input
|
|
398
|
builtin_mod.input = self._sys_eval_input
|
|
404
|
builtin_mod.input = self._sys_eval_input
|
|
399
|
|
|
405
|
|
|
400
|
reply_content[u'status'] = status
|
|
406
|
reply_content[u'status'] = status
|
|
401
|
|
|
407
|
|
|
402
|
# Return the execution counter so clients can display prompts
|
|
408
|
# Return the execution counter so clients can display prompts
|
|
403
|
reply_content['execution_count'] = shell.execution_count - 1
|
|
409
|
reply_content['execution_count'] = shell.execution_count - 1
|
|
404
|
|
|
410
|
|
|
405
|
# FIXME - fish exception info out of shell, possibly left there by
|
|
411
|
# FIXME - fish exception info out of shell, possibly left there by
|
|
406
|
# runlines. We'll need to clean up this logic later.
|
|
412
|
# runlines. We'll need to clean up this logic later.
|
|
407
|
if shell._reply_content is not None:
|
|
413
|
if shell._reply_content is not None:
|
|
408
|
reply_content.update(shell._reply_content)
|
|
414
|
reply_content.update(shell._reply_content)
|
|
409
|
e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
|
|
415
|
e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='execute')
|
|
410
|
reply_content['engine_info'] = e_info
|
|
416
|
reply_content['engine_info'] = e_info
|
|
411
|
# reset after use
|
|
417
|
# reset after use
|
|
412
|
shell._reply_content = None
|
|
418
|
shell._reply_content = None
|
|
413
|
|
|
419
|
|
|
414
|
if 'traceback' in reply_content:
|
|
420
|
if 'traceback' in reply_content:
|
|
415
|
self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
|
|
421
|
self.log.info("Exception in execute request:\n%s", '\n'.join(reply_content['traceback']))
|
|
416
|
|
|
422
|
|
|
417
|
|
|
423
|
|
|
418
|
# At this point, we can tell whether the main code execution succeeded
|
|
424
|
# At this point, we can tell whether the main code execution succeeded
|
|
419
|
# or not. If it did, we proceed to evaluate user_variables/expressions
|
|
425
|
# or not. If it did, we proceed to evaluate user_variables/expressions
|
|
420
|
if reply_content['status'] == 'ok':
|
|
426
|
if reply_content['status'] == 'ok':
|
|
421
|
reply_content[u'user_variables'] = \
|
|
427
|
reply_content[u'user_variables'] = \
|
|
422
|
shell.user_variables(content.get(u'user_variables', []))
|
|
428
|
shell.user_variables(content.get(u'user_variables', []))
|
|
423
|
reply_content[u'user_expressions'] = \
|
|
429
|
reply_content[u'user_expressions'] = \
|
|
424
|
shell.user_expressions(content.get(u'user_expressions', {}))
|
|
430
|
shell.user_expressions(content.get(u'user_expressions', {}))
|
|
425
|
else:
|
|
431
|
else:
|
|
426
|
# If there was an error, don't even try to compute variables or
|
|
432
|
# If there was an error, don't even try to compute variables or
|
|
427
|
# expressions
|
|
433
|
# expressions
|
|
428
|
reply_content[u'user_variables'] = {}
|
|
434
|
reply_content[u'user_variables'] = {}
|
|
429
|
reply_content[u'user_expressions'] = {}
|
|
435
|
reply_content[u'user_expressions'] = {}
|
|
430
|
|
|
436
|
|
|
431
|
# Payloads should be retrieved regardless of outcome, so we can both
|
|
437
|
# Payloads should be retrieved regardless of outcome, so we can both
|
|
432
|
# recover partial output (that could have been generated early in a
|
|
438
|
# recover partial output (that could have been generated early in a
|
|
433
|
# block, before an error) and clear the payload system always.
|
|
439
|
# block, before an error) and clear the payload system always.
|
|
434
|
reply_content[u'payload'] = shell.payload_manager.read_payload()
|
|
440
|
reply_content[u'payload'] = shell.payload_manager.read_payload()
|
|
435
|
# Be agressive about clearing the payload because we don't want
|
|
441
|
# Be agressive about clearing the payload because we don't want
|
|
436
|
# it to sit in memory until the next execute_request comes in.
|
|
442
|
# it to sit in memory until the next execute_request comes in.
|
|
437
|
shell.payload_manager.clear_payload()
|
|
443
|
shell.payload_manager.clear_payload()
|
|
438
|
|
|
444
|
|
|
439
|
# Flush output before sending the reply.
|
|
445
|
# Flush output before sending the reply.
|
|
440
|
sys.stdout.flush()
|
|
446
|
sys.stdout.flush()
|
|
441
|
sys.stderr.flush()
|
|
447
|
sys.stderr.flush()
|
|
442
|
# FIXME: on rare occasions, the flush doesn't seem to make it to the
|
|
448
|
# FIXME: on rare occasions, the flush doesn't seem to make it to the
|
|
443
|
# clients... This seems to mitigate the problem, but we definitely need
|
|
449
|
# clients... This seems to mitigate the problem, but we definitely need
|
|
444
|
# to better understand what's going on.
|
|
450
|
# to better understand what's going on.
|
|
445
|
if self._execute_sleep:
|
|
451
|
if self._execute_sleep:
|
|
446
|
time.sleep(self._execute_sleep)
|
|
452
|
time.sleep(self._execute_sleep)
|
|
447
|
|
|
453
|
|
|
448
|
# Send the reply.
|
|
454
|
# Send the reply.
|
|
449
|
reply_content = json_clean(reply_content)
|
|
455
|
reply_content = json_clean(reply_content)
|
|
450
|
|
|
456
|
|
|
451
|
md['status'] = reply_content['status']
|
|
457
|
md['status'] = reply_content['status']
|
|
452
|
if reply_content['status'] == 'error' and \
|
|
458
|
if reply_content['status'] == 'error' and \
|
|
453
|
reply_content['ename'] == 'UnmetDependency':
|
|
459
|
reply_content['ename'] == 'UnmetDependency':
|
|
454
|
md['dependencies_met'] = False
|
|
460
|
md['dependencies_met'] = False
|
|
455
|
|
|
461
|
|
|
456
|
reply_msg = self.session.send(stream, u'execute_reply',
|
|
462
|
reply_msg = self.session.send(stream, u'execute_reply',
|
|
457
|
reply_content, parent, metadata=md,
|
|
463
|
reply_content, parent, metadata=md,
|
|
458
|
ident=ident)
|
|
464
|
ident=ident)
|
|
459
|
|
|
465
|
|
|
460
|
self.log.debug("%s", reply_msg)
|
|
466
|
self.log.debug("%s", reply_msg)
|
|
461
|
|
|
467
|
|
|
462
|
if not silent and reply_msg['content']['status'] == u'error':
|
|
468
|
if not silent and reply_msg['content']['status'] == u'error':
|
|
463
|
self._abort_queues()
|
|
469
|
self._abort_queues()
|
|
464
|
|
|
470
|
|
|
465
|
self._publish_status(u'idle', parent)
|
|
471
|
self._publish_status(u'idle', parent)
|
|
466
|
|
|
472
|
|
|
467
|
def complete_request(self, stream, ident, parent):
|
|
473
|
def complete_request(self, stream, ident, parent):
|
|
468
|
txt, matches = self._complete(parent)
|
|
474
|
txt, matches = self._complete(parent)
|
|
469
|
matches = {'matches' : matches,
|
|
475
|
matches = {'matches' : matches,
|
|
470
|
'matched_text' : txt,
|
|
476
|
'matched_text' : txt,
|
|
471
|
'status' : 'ok'}
|
|
477
|
'status' : 'ok'}
|
|
472
|
matches = json_clean(matches)
|
|
478
|
matches = json_clean(matches)
|
|
473
|
completion_msg = self.session.send(stream, 'complete_reply',
|
|
479
|
completion_msg = self.session.send(stream, 'complete_reply',
|
|
474
|
matches, parent, ident)
|
|
480
|
matches, parent, ident)
|
|
475
|
self.log.debug("%s", completion_msg)
|
|
481
|
self.log.debug("%s", completion_msg)
|
|
476
|
|
|
482
|
|
|
477
|
def object_info_request(self, stream, ident, parent):
|
|
483
|
def object_info_request(self, stream, ident, parent):
|
|
478
|
content = parent['content']
|
|
484
|
content = parent['content']
|
|
479
|
object_info = self.shell.object_inspect(content['oname'],
|
|
485
|
object_info = self.shell.object_inspect(content['oname'],
|
|
480
|
detail_level = content.get('detail_level', 0)
|
|
486
|
detail_level = content.get('detail_level', 0)
|
|
481
|
)
|
|
487
|
)
|
|
482
|
# Before we send this object over, we scrub it for JSON usage
|
|
488
|
# Before we send this object over, we scrub it for JSON usage
|
|
483
|
oinfo = json_clean(object_info)
|
|
489
|
oinfo = json_clean(object_info)
|
|
484
|
msg = self.session.send(stream, 'object_info_reply',
|
|
490
|
msg = self.session.send(stream, 'object_info_reply',
|
|
485
|
oinfo, parent, ident)
|
|
491
|
oinfo, parent, ident)
|
|
486
|
self.log.debug("%s", msg)
|
|
492
|
self.log.debug("%s", msg)
|
|
487
|
|
|
493
|
|
|
488
|
def history_request(self, stream, ident, parent):
|
|
494
|
def history_request(self, stream, ident, parent):
|
|
489
|
# We need to pull these out, as passing **kwargs doesn't work with
|
|
495
|
# We need to pull these out, as passing **kwargs doesn't work with
|
|
490
|
# unicode keys before Python 2.6.5.
|
|
496
|
# unicode keys before Python 2.6.5.
|
|
491
|
hist_access_type = parent['content']['hist_access_type']
|
|
497
|
hist_access_type = parent['content']['hist_access_type']
|
|
492
|
raw = parent['content']['raw']
|
|
498
|
raw = parent['content']['raw']
|
|
493
|
output = parent['content']['output']
|
|
499
|
output = parent['content']['output']
|
|
494
|
if hist_access_type == 'tail':
|
|
500
|
if hist_access_type == 'tail':
|
|
495
|
n = parent['content']['n']
|
|
501
|
n = parent['content']['n']
|
|
496
|
hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
|
|
502
|
hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
|
|
497
|
include_latest=True)
|
|
503
|
include_latest=True)
|
|
498
|
|
|
504
|
|
|
499
|
elif hist_access_type == 'range':
|
|
505
|
elif hist_access_type == 'range':
|
|
500
|
session = parent['content']['session']
|
|
506
|
session = parent['content']['session']
|
|
501
|
start = parent['content']['start']
|
|
507
|
start = parent['content']['start']
|
|
502
|
stop = parent['content']['stop']
|
|
508
|
stop = parent['content']['stop']
|
|
503
|
hist = self.shell.history_manager.get_range(session, start, stop,
|
|
509
|
hist = self.shell.history_manager.get_range(session, start, stop,
|
|
504
|
raw=raw, output=output)
|
|
510
|
raw=raw, output=output)
|
|
505
|
|
|
511
|
|
|
506
|
elif hist_access_type == 'search':
|
|
512
|
elif hist_access_type == 'search':
|
|
507
|
n = parent['content'].get('n')
|
|
513
|
n = parent['content'].get('n')
|
|
508
|
unique = parent['content'].get('unique', False)
|
|
514
|
unique = parent['content'].get('unique', False)
|
|
509
|
pattern = parent['content']['pattern']
|
|
515
|
pattern = parent['content']['pattern']
|
|
510
|
hist = self.shell.history_manager.search(
|
|
516
|
hist = self.shell.history_manager.search(
|
|
511
|
pattern, raw=raw, output=output, n=n, unique=unique)
|
|
517
|
pattern, raw=raw, output=output, n=n, unique=unique)
|
|
512
|
|
|
518
|
|
|
513
|
else:
|
|
519
|
else:
|
|
514
|
hist = []
|
|
520
|
hist = []
|
|
515
|
hist = list(hist)
|
|
521
|
hist = list(hist)
|
|
516
|
content = {'history' : hist}
|
|
522
|
content = {'history' : hist}
|
|
517
|
content = json_clean(content)
|
|
523
|
content = json_clean(content)
|
|
518
|
msg = self.session.send(stream, 'history_reply',
|
|
524
|
msg = self.session.send(stream, 'history_reply',
|
|
519
|
content, parent, ident)
|
|
525
|
content, parent, ident)
|
|
520
|
self.log.debug("Sending history reply with %i entries", len(hist))
|
|
526
|
self.log.debug("Sending history reply with %i entries", len(hist))
|
|
521
|
|
|
527
|
|
|
522
|
def connect_request(self, stream, ident, parent):
|
|
528
|
def connect_request(self, stream, ident, parent):
|
|
523
|
if self._recorded_ports is not None:
|
|
529
|
if self._recorded_ports is not None:
|
|
524
|
content = self._recorded_ports.copy()
|
|
530
|
content = self._recorded_ports.copy()
|
|
525
|
else:
|
|
531
|
else:
|
|
526
|
content = {}
|
|
532
|
content = {}
|
|
527
|
msg = self.session.send(stream, 'connect_reply',
|
|
533
|
msg = self.session.send(stream, 'connect_reply',
|
|
528
|
content, parent, ident)
|
|
534
|
content, parent, ident)
|
|
529
|
self.log.debug("%s", msg)
|
|
535
|
self.log.debug("%s", msg)
|
|
530
|
|
|
536
|
|
|
531
|
def kernel_info_request(self, stream, ident, parent):
|
|
537
|
def kernel_info_request(self, stream, ident, parent):
|
|
532
|
vinfo = {
|
|
538
|
vinfo = {
|
|
533
|
'protocol_version': protocol_version,
|
|
539
|
'protocol_version': protocol_version,
|
|
534
|
'ipython_version': ipython_version,
|
|
540
|
'ipython_version': ipython_version,
|
|
535
|
'language_version': language_version,
|
|
541
|
'language_version': language_version,
|
|
536
|
'language': 'python',
|
|
542
|
'language': 'python',
|
|
537
|
}
|
|
543
|
}
|
|
538
|
msg = self.session.send(stream, 'kernel_info_reply',
|
|
544
|
msg = self.session.send(stream, 'kernel_info_reply',
|
|
539
|
vinfo, parent, ident)
|
|
545
|
vinfo, parent, ident)
|
|
540
|
self.log.debug("%s", msg)
|
|
546
|
self.log.debug("%s", msg)
|
|
541
|
|
|
547
|
|
|
542
|
def shutdown_request(self, stream, ident, parent):
|
|
548
|
def shutdown_request(self, stream, ident, parent):
|
|
543
|
self.shell.exit_now = True
|
|
549
|
self.shell.exit_now = True
|
|
544
|
content = dict(status='ok')
|
|
550
|
content = dict(status='ok')
|
|
545
|
content.update(parent['content'])
|
|
551
|
content.update(parent['content'])
|
|
546
|
self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
|
|
552
|
self.session.send(stream, u'shutdown_reply', content, parent, ident=ident)
|
|
547
|
# same content, but different msg_id for broadcasting on IOPub
|
|
553
|
# same content, but different msg_id for broadcasting on IOPub
|
|
548
|
self._shutdown_message = self.session.msg(u'shutdown_reply',
|
|
554
|
self._shutdown_message = self.session.msg(u'shutdown_reply',
|
|
549
|
content, parent
|
|
555
|
content, parent
|
|
550
|
)
|
|
556
|
)
|
|
551
|
|
|
557
|
|
|
552
|
self._at_shutdown()
|
|
558
|
self._at_shutdown()
|
|
553
|
# call sys.exit after a short delay
|
|
559
|
# call sys.exit after a short delay
|
|
554
|
loop = ioloop.IOLoop.instance()
|
|
560
|
loop = ioloop.IOLoop.instance()
|
|
555
|
loop.add_timeout(time.time()+0.1, loop.stop)
|
|
561
|
loop.add_timeout(time.time()+0.1, loop.stop)
|
|
556
|
|
|
562
|
|
|
557
|
#---------------------------------------------------------------------------
|
|
563
|
#---------------------------------------------------------------------------
|
|
558
|
# Engine methods
|
|
564
|
# Engine methods
|
|
559
|
#---------------------------------------------------------------------------
|
|
565
|
#---------------------------------------------------------------------------
|
|
560
|
|
|
566
|
|
|
561
|
def apply_request(self, stream, ident, parent):
|
|
567
|
def apply_request(self, stream, ident, parent):
|
|
562
|
try:
|
|
568
|
try:
|
|
563
|
content = parent[u'content']
|
|
569
|
content = parent[u'content']
|
|
564
|
bufs = parent[u'buffers']
|
|
570
|
bufs = parent[u'buffers']
|
|
565
|
msg_id = parent['header']['msg_id']
|
|
571
|
msg_id = parent['header']['msg_id']
|
|
566
|
except:
|
|
572
|
except:
|
|
567
|
self.log.error("Got bad msg: %s", parent, exc_info=True)
|
|
573
|
self.log.error("Got bad msg: %s", parent, exc_info=True)
|
|
568
|
return
|
|
574
|
return
|
|
569
|
|
|
575
|
|
|
570
|
self._publish_status(u'busy', parent)
|
|
576
|
self._publish_status(u'busy', parent)
|
|
571
|
|
|
577
|
|
|
572
|
# Set the parent message of the display hook and out streams.
|
|
578
|
# Set the parent message of the display hook and out streams.
|
|
573
|
shell = self.shell
|
|
579
|
shell = self.shell
|
|
574
|
shell.set_parent(parent)
|
|
580
|
shell.set_parent(parent)
|
|
575
|
|
|
581
|
|
|
576
|
# pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
|
|
582
|
# pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
|
|
577
|
# self.iopub_socket.send(pyin_msg)
|
|
583
|
# self.iopub_socket.send(pyin_msg)
|
|
578
|
# self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
|
|
584
|
# self.session.send(self.iopub_socket, u'pyin', {u'code':code},parent=parent)
|
|
579
|
md = self._make_metadata(parent['metadata'])
|
|
585
|
md = self._make_metadata(parent['metadata'])
|
|
580
|
try:
|
|
586
|
try:
|
|
581
|
working = shell.user_ns
|
|
587
|
working = shell.user_ns
|
|
582
|
|
|
588
|
|
|
583
|
prefix = "_"+str(msg_id).replace("-","")+"_"
|
|
589
|
prefix = "_"+str(msg_id).replace("-","")+"_"
|
|
584
|
|
|
590
|
|
|
585
|
f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
|
|
591
|
f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
|
|
586
|
|
|
592
|
|
|
587
|
fname = getattr(f, '__name__', 'f')
|
|
593
|
fname = getattr(f, '__name__', 'f')
|
|
588
|
|
|
594
|
|
|
589
|
fname = prefix+"f"
|
|
595
|
fname = prefix+"f"
|
|
590
|
argname = prefix+"args"
|
|
596
|
argname = prefix+"args"
|
|
591
|
kwargname = prefix+"kwargs"
|
|
597
|
kwargname = prefix+"kwargs"
|
|
592
|
resultname = prefix+"result"
|
|
598
|
resultname = prefix+"result"
|
|
593
|
|
|
599
|
|
|
594
|
ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
|
|
600
|
ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
|
|
595
|
# print ns
|
|
601
|
# print ns
|
|
596
|
working.update(ns)
|
|
602
|
working.update(ns)
|
|
597
|
code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
|
|
603
|
code = "%s = %s(*%s,**%s)" % (resultname, fname, argname, kwargname)
|
|
598
|
try:
|
|
604
|
try:
|
|
599
|
exec(code, shell.user_global_ns, shell.user_ns)
|
|
605
|
exec(code, shell.user_global_ns, shell.user_ns)
|
|
600
|
result = working.get(resultname)
|
|
606
|
result = working.get(resultname)
|
|
601
|
finally:
|
|
607
|
finally:
|
|
602
|
for key in ns:
|
|
608
|
for key in ns:
|
|
603
|
working.pop(key)
|
|
609
|
working.pop(key)
|
|
604
|
|
|
610
|
|
|
605
|
result_buf = serialize_object(result,
|
|
611
|
result_buf = serialize_object(result,
|
|
606
|
buffer_threshold=self.session.buffer_threshold,
|
|
612
|
buffer_threshold=self.session.buffer_threshold,
|
|
607
|
item_threshold=self.session.item_threshold,
|
|
613
|
item_threshold=self.session.item_threshold,
|
|
608
|
)
|
|
614
|
)
|
|
609
|
|
|
615
|
|
|
610
|
except:
|
|
616
|
except:
|
|
611
|
# invoke IPython traceback formatting
|
|
617
|
# invoke IPython traceback formatting
|
|
612
|
shell.showtraceback()
|
|
618
|
shell.showtraceback()
|
|
613
|
# FIXME - fish exception info out of shell, possibly left there by
|
|
619
|
# FIXME - fish exception info out of shell, possibly left there by
|
|
614
|
# run_code. We'll need to clean up this logic later.
|
|
620
|
# run_code. We'll need to clean up this logic later.
|
|
615
|
reply_content = {}
|
|
621
|
reply_content = {}
|
|
616
|
if shell._reply_content is not None:
|
|
622
|
if shell._reply_content is not None:
|
|
617
|
reply_content.update(shell._reply_content)
|
|
623
|
reply_content.update(shell._reply_content)
|
|
618
|
e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
|
|
624
|
e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method='apply')
|
|
619
|
reply_content['engine_info'] = e_info
|
|
625
|
reply_content['engine_info'] = e_info
|
|
620
|
# reset after use
|
|
626
|
# reset after use
|
|
621
|
shell._reply_content = None
|
|
627
|
shell._reply_content = None
|
|
622
|
|
|
628
|
|
|
623
|
self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
|
|
629
|
self.session.send(self.iopub_socket, u'pyerr', reply_content, parent=parent,
|
|
624
|
ident=self._topic('pyerr'))
|
|
630
|
ident=self._topic('pyerr'))
|
|
625
|
self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
|
|
631
|
self.log.info("Exception in apply request:\n%s", '\n'.join(reply_content['traceback']))
|
|
626
|
result_buf = []
|
|
632
|
result_buf = []
|
|
627
|
|
|
633
|
|
|
628
|
if reply_content['ename'] == 'UnmetDependency':
|
|
634
|
if reply_content['ename'] == 'UnmetDependency':
|
|
629
|
md['dependencies_met'] = False
|
|
635
|
md['dependencies_met'] = False
|
|
630
|
else:
|
|
636
|
else:
|
|
631
|
reply_content = {'status' : 'ok'}
|
|
637
|
reply_content = {'status' : 'ok'}
|
|
632
|
|
|
638
|
|
|
633
|
# put 'ok'/'error' status in header, for scheduler introspection:
|
|
639
|
# put 'ok'/'error' status in header, for scheduler introspection:
|
|
634
|
md['status'] = reply_content['status']
|
|
640
|
md['status'] = reply_content['status']
|
|
635
|
|
|
641
|
|
|
636
|
# flush i/o
|
|
642
|
# flush i/o
|
|
637
|
sys.stdout.flush()
|
|
643
|
sys.stdout.flush()
|
|
638
|
sys.stderr.flush()
|
|
644
|
sys.stderr.flush()
|
|
639
|
|
|
645
|
|
|
640
|
reply_msg = self.session.send(stream, u'apply_reply', reply_content,
|
|
646
|
reply_msg = self.session.send(stream, u'apply_reply', reply_content,
|
|
641
|
parent=parent, ident=ident,buffers=result_buf, metadata=md)
|
|
647
|
parent=parent, ident=ident,buffers=result_buf, metadata=md)
|
|
642
|
|
|
648
|
|
|
643
|
self._publish_status(u'idle', parent)
|
|
649
|
self._publish_status(u'idle', parent)
|
|
644
|
|
|
650
|
|
|
645
|
#---------------------------------------------------------------------------
|
|
651
|
#---------------------------------------------------------------------------
|
|
646
|
# Control messages
|
|
652
|
# Control messages
|
|
647
|
#---------------------------------------------------------------------------
|
|
653
|
#---------------------------------------------------------------------------
|
|
648
|
|
|
654
|
|
|
649
|
def abort_request(self, stream, ident, parent):
|
|
655
|
def abort_request(self, stream, ident, parent):
|
|
650
|
"""abort a specifig msg by id"""
|
|
656
|
"""abort a specifig msg by id"""
|
|
651
|
msg_ids = parent['content'].get('msg_ids', None)
|
|
657
|
msg_ids = parent['content'].get('msg_ids', None)
|
|
652
|
if isinstance(msg_ids, string_types):
|
|
658
|
if isinstance(msg_ids, string_types):
|
|
653
|
msg_ids = [msg_ids]
|
|
659
|
msg_ids = [msg_ids]
|
|
654
|
if not msg_ids:
|
|
660
|
if not msg_ids:
|
|
655
|
self.abort_queues()
|
|
661
|
self.abort_queues()
|
|
656
|
for mid in msg_ids:
|
|
662
|
for mid in msg_ids:
|
|
657
|
self.aborted.add(str(mid))
|
|
663
|
self.aborted.add(str(mid))
|
|
658
|
|
|
664
|
|
|
659
|
content = dict(status='ok')
|
|
665
|
content = dict(status='ok')
|
|
660
|
reply_msg = self.session.send(stream, 'abort_reply', content=content,
|
|
666
|
reply_msg = self.session.send(stream, 'abort_reply', content=content,
|
|
661
|
parent=parent, ident=ident)
|
|
667
|
parent=parent, ident=ident)
|
|
662
|
self.log.debug("%s", reply_msg)
|
|
668
|
self.log.debug("%s", reply_msg)
|
|
663
|
|
|
669
|
|
|
664
|
def clear_request(self, stream, idents, parent):
|
|
670
|
def clear_request(self, stream, idents, parent):
|
|
665
|
"""Clear our namespace."""
|
|
671
|
"""Clear our namespace."""
|
|
666
|
self.shell.reset(False)
|
|
672
|
self.shell.reset(False)
|
|
667
|
msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
|
|
673
|
msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
|
|
668
|
content = dict(status='ok'))
|
|
674
|
content = dict(status='ok'))
|
|
669
|
|
|
675
|
|
|
670
|
|
|
676
|
|
|
671
|
#---------------------------------------------------------------------------
|
|
677
|
#---------------------------------------------------------------------------
|
|
672
|
# Protected interface
|
|
678
|
# Protected interface
|
|
673
|
#---------------------------------------------------------------------------
|
|
679
|
#---------------------------------------------------------------------------
|
|
674
|
|
|
680
|
|
|
675
|
def _wrap_exception(self, method=None):
|
|
681
|
def _wrap_exception(self, method=None):
|
|
676
|
# import here, because _wrap_exception is only used in parallel,
|
|
682
|
# import here, because _wrap_exception is only used in parallel,
|
|
677
|
# and parallel has higher min pyzmq version
|
|
683
|
# and parallel has higher min pyzmq version
|
|
678
|
from IPython.parallel.error import wrap_exception
|
|
684
|
from IPython.parallel.error import wrap_exception
|
|
679
|
e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
|
|
685
|
e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
|
|
680
|
content = wrap_exception(e_info)
|
|
686
|
content = wrap_exception(e_info)
|
|
681
|
return content
|
|
687
|
return content
|
|
682
|
|
|
688
|
|
|
683
|
def _topic(self, topic):
|
|
689
|
def _topic(self, topic):
|
|
684
|
"""prefixed topic for IOPub messages"""
|
|
690
|
"""prefixed topic for IOPub messages"""
|
|
685
|
if self.int_id >= 0:
|
|
691
|
if self.int_id >= 0:
|
|
686
|
base = "engine.%i" % self.int_id
|
|
692
|
base = "engine.%i" % self.int_id
|
|
687
|
else:
|
|
693
|
else:
|
|
688
|
base = "kernel.%s" % self.ident
|
|
694
|
base = "kernel.%s" % self.ident
|
|
689
|
|
|
695
|
|
|
690
|
return py3compat.cast_bytes("%s.%s" % (base, topic))
|
|
696
|
return py3compat.cast_bytes("%s.%s" % (base, topic))
|
|
691
|
|
|
697
|
|
|
692
|
def _abort_queues(self):
|
|
698
|
def _abort_queues(self):
|
|
693
|
for stream in self.shell_streams:
|
|
699
|
for stream in self.shell_streams:
|
|
694
|
if stream:
|
|
700
|
if stream:
|
|
695
|
self._abort_queue(stream)
|
|
701
|
self._abort_queue(stream)
|
|
696
|
|
|
702
|
|
|
697
|
def _abort_queue(self, stream):
|
|
703
|
def _abort_queue(self, stream):
|
|
698
|
poller = zmq.Poller()
|
|
704
|
poller = zmq.Poller()
|
|
699
|
poller.register(stream.socket, zmq.POLLIN)
|
|
705
|
poller.register(stream.socket, zmq.POLLIN)
|
|
700
|
while True:
|
|
706
|
while True:
|
|
701
|
idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
|
|
707
|
idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
|
|
702
|
if msg is None:
|
|
708
|
if msg is None:
|
|
703
|
return
|
|
709
|
return
|
|
704
|
|
|
710
|
|
|
705
|
self.log.info("Aborting:")
|
|
711
|
self.log.info("Aborting:")
|
|
706
|
self.log.info("%s", msg)
|
|
712
|
self.log.info("%s", msg)
|
|
707
|
msg_type = msg['header']['msg_type']
|
|
713
|
msg_type = msg['header']['msg_type']
|
|
708
|
reply_type = msg_type.split('_')[0] + '_reply'
|
|
714
|
reply_type = msg_type.split('_')[0] + '_reply'
|
|
709
|
|
|
715
|
|
|
710
|
status = {'status' : 'aborted'}
|
|
716
|
status = {'status' : 'aborted'}
|
|
711
|
md = {'engine' : self.ident}
|
|
717
|
md = {'engine' : self.ident}
|
|
712
|
md.update(status)
|
|
718
|
md.update(status)
|
|
713
|
reply_msg = self.session.send(stream, reply_type, metadata=md,
|
|
719
|
reply_msg = self.session.send(stream, reply_type, metadata=md,
|
|
714
|
content=status, parent=msg, ident=idents)
|
|
720
|
content=status, parent=msg, ident=idents)
|
|
715
|
self.log.debug("%s", reply_msg)
|
|
721
|
self.log.debug("%s", reply_msg)
|
|
716
|
# We need to wait a bit for requests to come in. This can probably
|
|
722
|
# We need to wait a bit for requests to come in. This can probably
|
|
717
|
# be set shorter for true asynchronous clients.
|
|
723
|
# be set shorter for true asynchronous clients.
|
|
718
|
poller.poll(50)
|
|
724
|
poller.poll(50)
|
|
719
|
|
|
725
|
|
|
720
|
|
|
726
|
|
|
721
|
def _no_raw_input(self):
|
|
727
|
def _no_raw_input(self):
|
|
722
|
"""Raise StdinNotImplentedError if active frontend doesn't support
|
|
728
|
"""Raise StdinNotImplentedError if active frontend doesn't support
|
|
723
|
stdin."""
|
|
729
|
stdin."""
|
|
724
|
raise StdinNotImplementedError("raw_input was called, but this "
|
|
730
|
raise StdinNotImplementedError("raw_input was called, but this "
|
|
725
|
"frontend does not support stdin.")
|
|
731
|
"frontend does not support stdin.")
|
|
726
|
|
|
732
|
|
|
727
|
def _raw_input(self, prompt, ident, parent):
|
|
733
|
def _raw_input(self, prompt, ident, parent):
|
|
728
|
# Flush output before making the request.
|
|
734
|
# Flush output before making the request.
|
|
729
|
sys.stderr.flush()
|
|
735
|
sys.stderr.flush()
|
|
730
|
sys.stdout.flush()
|
|
736
|
sys.stdout.flush()
|
|
731
|
# flush the stdin socket, to purge stale replies
|
|
737
|
# flush the stdin socket, to purge stale replies
|
|
732
|
while True:
|
|
738
|
while True:
|
|
733
|
try:
|
|
739
|
try:
|
|
734
|
self.stdin_socket.recv_multipart(zmq.NOBLOCK)
|
|
740
|
self.stdin_socket.recv_multipart(zmq.NOBLOCK)
|
|
735
|
except zmq.ZMQError as e:
|
|
741
|
except zmq.ZMQError as e:
|
|
736
|
if e.errno == zmq.EAGAIN:
|
|
742
|
if e.errno == zmq.EAGAIN:
|
|
737
|
break
|
|
743
|
break
|
|
738
|
else:
|
|
744
|
else:
|
|
739
|
raise
|
|
745
|
raise
|
|
740
|
|
|
746
|
|
|
741
|
# Send the input request.
|
|
747
|
# Send the input request.
|
|
742
|
content = json_clean(dict(prompt=prompt))
|
|
748
|
content = json_clean(dict(prompt=prompt))
|
|
743
|
self.session.send(self.stdin_socket, u'input_request', content, parent,
|
|
749
|
self.session.send(self.stdin_socket, u'input_request', content, parent,
|
|
744
|
ident=ident)
|
|
750
|
ident=ident)
|
|
745
|
|
|
751
|
|
|
746
|
# Await a response.
|
|
752
|
# Await a response.
|
|
747
|
while True:
|
|
753
|
while True:
|
|
748
|
try:
|
|
754
|
try:
|
|
749
|
ident, reply = self.session.recv(self.stdin_socket, 0)
|
|
755
|
ident, reply = self.session.recv(self.stdin_socket, 0)
|
|
750
|
except Exception:
|
|
756
|
except Exception:
|
|
751
|
self.log.warn("Invalid Message:", exc_info=True)
|
|
757
|
self.log.warn("Invalid Message:", exc_info=True)
|
|
752
|
except KeyboardInterrupt:
|
|
758
|
except KeyboardInterrupt:
|
|
753
|
# re-raise KeyboardInterrupt, to truncate traceback
|
|
759
|
# re-raise KeyboardInterrupt, to truncate traceback
|
|
754
|
raise KeyboardInterrupt
|
|
760
|
raise KeyboardInterrupt
|
|
755
|
else:
|
|
761
|
else:
|
|
756
|
break
|
|
762
|
break
|
|
757
|
try:
|
|
763
|
try:
|
|
758
|
value = py3compat.unicode_to_str(reply['content']['value'])
|
|
764
|
value = py3compat.unicode_to_str(reply['content']['value'])
|
|
759
|
except:
|
|
765
|
except:
|
|
760
|
self.log.error("Got bad raw_input reply: ")
|
|
766
|
self.log.error("Got bad raw_input reply: ")
|
|
761
|
self.log.error("%s", parent)
|
|
767
|
self.log.error("%s", parent)
|
|
762
|
value = ''
|
|
768
|
value = ''
|
|
763
|
if value == '\x04':
|
|
769
|
if value == '\x04':
|
|
764
|
# EOF
|
|
770
|
# EOF
|
|
765
|
raise EOFError
|
|
771
|
raise EOFError
|
|
766
|
return value
|
|
772
|
return value
|
|
767
|
|
|
773
|
|
|
768
|
def _complete(self, msg):
|
|
774
|
def _complete(self, msg):
|
|
769
|
c = msg['content']
|
|
775
|
c = msg['content']
|
|
770
|
try:
|
|
776
|
try:
|
|
771
|
cpos = int(c['cursor_pos'])
|
|
777
|
cpos = int(c['cursor_pos'])
|
|
772
|
except:
|
|
778
|
except:
|
|
773
|
# If we don't get something that we can convert to an integer, at
|
|
779
|
# If we don't get something that we can convert to an integer, at
|
|
774
|
# least attempt the completion guessing the cursor is at the end of
|
|
780
|
# least attempt the completion guessing the cursor is at the end of
|
|
775
|
# the text, if there's any, and otherwise of the line
|
|
781
|
# the text, if there's any, and otherwise of the line
|
|
776
|
cpos = len(c['text'])
|
|
782
|
cpos = len(c['text'])
|
|
777
|
if cpos==0:
|
|
783
|
if cpos==0:
|
|
778
|
cpos = len(c['line'])
|
|
784
|
cpos = len(c['line'])
|
|
779
|
return self.shell.complete(c['text'], c['line'], cpos)
|
|
785
|
return self.shell.complete(c['text'], c['line'], cpos)
|
|
780
|
|
|
786
|
|
|
781
|
def _at_shutdown(self):
|
|
787
|
def _at_shutdown(self):
|
|
782
|
"""Actions taken at shutdown by the kernel, called by python's atexit.
|
|
788
|
"""Actions taken at shutdown by the kernel, called by python's atexit.
|
|
783
|
"""
|
|
789
|
"""
|
|
784
|
# io.rprint("Kernel at_shutdown") # dbg
|
|
790
|
# io.rprint("Kernel at_shutdown") # dbg
|
|
785
|
if self._shutdown_message is not None:
|
|
791
|
if self._shutdown_message is not None:
|
|
786
|
self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
|
|
792
|
self.session.send(self.iopub_socket, self._shutdown_message, ident=self._topic('shutdown'))
|
|
787
|
self.log.debug("%s", self._shutdown_message)
|
|
793
|
self.log.debug("%s", self._shutdown_message)
|
|
788
|
[ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
|
|
794
|
[ s.flush(zmq.POLLOUT) for s in self.shell_streams ]
|
|
789
|
|
|
795
|
|