|
@@
-114,13
+114,11
b' class DisplayHook(object):'
|
|
114
|
self.parent_header = {}
|
|
114
|
self.parent_header = {}
|
|
115
|
|
|
115
|
|
|
116
|
def __call__(self, obj):
|
|
116
|
def __call__(self, obj):
|
|
117
|
if obj is None:
|
|
117
|
if obj is not None:
|
|
118
|
return
|
|
118
|
__builtin__._ = obj
|
|
119
|
|
|
119
|
msg = self.session.msg(u'pyout', {u'data':repr(obj)},
|
|
120
|
__builtin__._ = obj
|
|
120
|
parent=self.parent_header)
|
|
121
|
msg = self.session.msg(u'pyout', {u'data':repr(obj)},
|
|
121
|
self.pub_socket.send_json(msg)
|
|
122
|
parent=self.parent_header)
|
|
|
|
|
123
|
self.pub_socket.send_json(msg)
|
|
|
|
|
124
|
|
|
122
|
|
|
125
|
def set_parent(self, parent):
|
|
123
|
def set_parent(self, parent):
|
|
126
|
self.parent_header = extract_header(parent)
|
|
124
|
self.parent_header = extract_header(parent)
|
|
@@
-128,6
+126,22
b' class DisplayHook(object):'
|
|
128
|
|
|
126
|
|
|
129
|
class Kernel(object):
|
|
127
|
class Kernel(object):
|
|
130
|
|
|
128
|
|
|
|
|
|
129
|
# The global kernel instance.
|
|
|
|
|
130
|
_kernel = None
|
|
|
|
|
131
|
|
|
|
|
|
132
|
# Maps user-friendly backend names to matplotlib backend identifiers.
|
|
|
|
|
133
|
_pylab_map = { 'tk': 'TkAgg',
|
|
|
|
|
134
|
'gtk': 'GTKAgg',
|
|
|
|
|
135
|
'wx': 'WXAgg',
|
|
|
|
|
136
|
'qt': 'Qt4Agg', # qt3 not supported
|
|
|
|
|
137
|
'qt4': 'Qt4Agg',
|
|
|
|
|
138
|
'payload-svg' : \
|
|
|
|
|
139
|
'module://IPython.zmq.pylab.backend_payload_svg' }
|
|
|
|
|
140
|
|
|
|
|
|
141
|
#---------------------------------------------------------------------------
|
|
|
|
|
142
|
# Kernel interface
|
|
|
|
|
143
|
#---------------------------------------------------------------------------
|
|
|
|
|
144
|
|
|
131
|
def __init__(self, session, reply_socket, pub_socket, req_socket):
|
|
145
|
def __init__(self, session, reply_socket, pub_socket, req_socket):
|
|
132
|
self.session = session
|
|
146
|
self.session = session
|
|
133
|
self.reply_socket = reply_socket
|
|
147
|
self.reply_socket = reply_socket
|
|
@@
-137,6
+151,9
b' class Kernel(object):'
|
|
137
|
self.history = []
|
|
151
|
self.history = []
|
|
138
|
self.compiler = CommandCompiler()
|
|
152
|
self.compiler = CommandCompiler()
|
|
139
|
self.completer = KernelCompleter(self.user_ns)
|
|
153
|
self.completer = KernelCompleter(self.user_ns)
|
|
|
|
|
154
|
|
|
|
|
|
155
|
# Protected variables.
|
|
|
|
|
156
|
self._exec_payload = {}
|
|
140
|
|
|
157
|
|
|
141
|
# Build dict of handlers for message types
|
|
158
|
# Build dict of handlers for message types
|
|
142
|
msg_types = [ 'execute_request', 'complete_request',
|
|
159
|
msg_types = [ 'execute_request', 'complete_request',
|
|
@@
-145,27
+162,83
b' class Kernel(object):'
|
|
145
|
for msg_type in msg_types:
|
|
162
|
for msg_type in msg_types:
|
|
146
|
self.handlers[msg_type] = getattr(self, msg_type)
|
|
163
|
self.handlers[msg_type] = getattr(self, msg_type)
|
|
147
|
|
|
164
|
|
|
148
|
def abort_queue(self):
|
|
165
|
def add_exec_payload(self, key, value):
|
|
|
|
|
166
|
""" Adds a key/value pair to the execute payload.
|
|
|
|
|
167
|
"""
|
|
|
|
|
168
|
self._exec_payload[key] = value
|
|
|
|
|
169
|
|
|
|
|
|
170
|
def activate_pylab(self, backend=None, import_all=True):
|
|
|
|
|
171
|
""" Activates pylab in this kernel's namespace.
|
|
|
|
|
172
|
|
|
|
|
|
173
|
Parameters:
|
|
|
|
|
174
|
-----------
|
|
|
|
|
175
|
backend : str, optional
|
|
|
|
|
176
|
A valid backend name.
|
|
|
|
|
177
|
|
|
|
|
|
178
|
import_all : bool, optional
|
|
|
|
|
179
|
If true, an 'import *' is done from numpy and pylab.
|
|
|
|
|
180
|
"""
|
|
|
|
|
181
|
# FIXME: This is adapted from IPython.lib.pylabtools.pylab_activate.
|
|
|
|
|
182
|
# Common funtionality should be refactored.
|
|
|
|
|
183
|
|
|
|
|
|
184
|
import matplotlib
|
|
|
|
|
185
|
|
|
|
|
|
186
|
# We must set the desired backend before importing pylab.
|
|
|
|
|
187
|
if backend:
|
|
|
|
|
188
|
matplotlib.use(self._pylab_map[backend])
|
|
|
|
|
189
|
|
|
|
|
|
190
|
# This must be imported last in the matplotlib series, after
|
|
|
|
|
191
|
# backend/interactivity choices have been made.
|
|
|
|
|
192
|
import matplotlib.pylab as pylab
|
|
|
|
|
193
|
|
|
|
|
|
194
|
# Import numpy as np/pyplot as plt are conventions we're trying to
|
|
|
|
|
195
|
# somewhat standardize on. Making them available to users by default
|
|
|
|
|
196
|
# will greatly help this.
|
|
|
|
|
197
|
exec ("import numpy\n"
|
|
|
|
|
198
|
"import matplotlib\n"
|
|
|
|
|
199
|
"from matplotlib import pylab, mlab, pyplot\n"
|
|
|
|
|
200
|
"np = numpy\n"
|
|
|
|
|
201
|
"plt = pyplot\n"
|
|
|
|
|
202
|
) in self.user_ns
|
|
|
|
|
203
|
|
|
|
|
|
204
|
if import_all:
|
|
|
|
|
205
|
exec("from matplotlib.pylab import *\n"
|
|
|
|
|
206
|
"from numpy import *\n") in self.user_ns
|
|
|
|
|
207
|
|
|
|
|
|
208
|
matplotlib.interactive(True)
|
|
|
|
|
209
|
|
|
|
|
|
210
|
@classmethod
|
|
|
|
|
211
|
def get_kernel(cls):
|
|
|
|
|
212
|
""" Return the global kernel instance or raise a RuntimeError if it does
|
|
|
|
|
213
|
not exist.
|
|
|
|
|
214
|
"""
|
|
|
|
|
215
|
if cls._kernel is None:
|
|
|
|
|
216
|
raise RuntimeError("Kernel not started!")
|
|
|
|
|
217
|
else:
|
|
|
|
|
218
|
return cls._kernel
|
|
|
|
|
219
|
|
|
|
|
|
220
|
def start(self):
|
|
|
|
|
221
|
""" Start the kernel main loop.
|
|
|
|
|
222
|
"""
|
|
|
|
|
223
|
# Set the global kernel instance.
|
|
|
|
|
224
|
Kernel._kernel = self
|
|
|
|
|
225
|
|
|
149
|
while True:
|
|
226
|
while True:
|
|
150
|
try:
|
|
227
|
ident = self.reply_socket.recv()
|
|
151
|
ident = self.reply_socket.recv(zmq.NOBLOCK)
|
|
228
|
assert self.reply_socket.rcvmore(), "Missing message part."
|
|
152
|
except zmq.ZMQError, e:
|
|
229
|
msg = self.reply_socket.recv_json()
|
|
153
|
if e.errno == zmq.EAGAIN:
|
|
230
|
omsg = Message(msg)
|
|
154
|
break
|
|
231
|
print>>sys.__stdout__
|
|
|
|
|
232
|
print>>sys.__stdout__, omsg
|
|
|
|
|
233
|
handler = self.handlers.get(omsg.msg_type, None)
|
|
|
|
|
234
|
if handler is None:
|
|
|
|
|
235
|
print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
|
|
155
|
else:
|
|
236
|
else:
|
|
156
|
assert self.reply_socket.rcvmore(), "Unexpected missing message part."
|
|
237
|
handler(ident, omsg)
|
|
157
|
msg = self.reply_socket.recv_json()
|
|
238
|
|
|
158
|
print>>sys.__stdout__, "Aborting:"
|
|
239
|
#---------------------------------------------------------------------------
|
|
159
|
print>>sys.__stdout__, Message(msg)
|
|
240
|
# Kernel request handlers
|
|
160
|
msg_type = msg['msg_type']
|
|
241
|
#---------------------------------------------------------------------------
|
|
161
|
reply_type = msg_type.split('_')[0] + '_reply'
|
|
|
|
|
162
|
reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
|
|
|
|
|
163
|
print>>sys.__stdout__, Message(reply_msg)
|
|
|
|
|
164
|
self.reply_socket.send(ident,zmq.SNDMORE)
|
|
|
|
|
165
|
self.reply_socket.send_json(reply_msg)
|
|
|
|
|
166
|
# We need to wait a bit for requests to come in. This can probably
|
|
|
|
|
167
|
# be set shorter for true asynchronous clients.
|
|
|
|
|
168
|
time.sleep(0.1)
|
|
|
|
|
169
|
|
|
242
|
|
|
170
|
def execute_request(self, ident, parent):
|
|
243
|
def execute_request(self, ident, parent):
|
|
171
|
try:
|
|
244
|
try:
|
|
@@
-177,12
+250,15
b' class Kernel(object):'
|
|
177
|
pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
|
|
250
|
pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
|
|
178
|
self.pub_socket.send_json(pyin_msg)
|
|
251
|
self.pub_socket.send_json(pyin_msg)
|
|
179
|
|
|
252
|
|
|
|
|
|
253
|
# Clear the execute payload from the last request.
|
|
|
|
|
254
|
self._exec_payload = {}
|
|
|
|
|
255
|
|
|
180
|
try:
|
|
256
|
try:
|
|
181
|
comp_code = self.compiler(code, '<zmq-kernel>')
|
|
257
|
comp_code = self.compiler(code, '<zmq-kernel>')
|
|
182
|
|
|
258
|
|
|
183
|
# Replace raw_input. Note that is not sufficient to replace
|
|
259
|
# Replace raw_input. Note that is not sufficient to replace
|
|
184
|
# raw_input in the user namespace.
|
|
260
|
# raw_input in the user namespace.
|
|
185
|
raw_input = lambda prompt='': self.raw_input(prompt, ident, parent)
|
|
261
|
raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
|
|
186
|
__builtin__.raw_input = raw_input
|
|
262
|
__builtin__.raw_input = raw_input
|
|
187
|
|
|
263
|
|
|
188
|
# Configure the display hook.
|
|
264
|
# Configure the display hook.
|
|
@@
-203,7
+279,7
b' class Kernel(object):'
|
|
203
|
self.pub_socket.send_json(exc_msg)
|
|
279
|
self.pub_socket.send_json(exc_msg)
|
|
204
|
reply_content = exc_content
|
|
280
|
reply_content = exc_content
|
|
205
|
else:
|
|
281
|
else:
|
|
206
|
reply_content = {'status' : 'ok'}
|
|
282
|
reply_content = { 'status' : 'ok', 'payload' : self._exec_payload }
|
|
207
|
|
|
283
|
|
|
208
|
# Flush output before sending the reply.
|
|
284
|
# Flush output before sending the reply.
|
|
209
|
sys.stderr.flush()
|
|
285
|
sys.stderr.flush()
|
|
@@
-215,9
+291,49
b' class Kernel(object):'
|
|
215
|
self.reply_socket.send(ident, zmq.SNDMORE)
|
|
291
|
self.reply_socket.send(ident, zmq.SNDMORE)
|
|
216
|
self.reply_socket.send_json(reply_msg)
|
|
292
|
self.reply_socket.send_json(reply_msg)
|
|
217
|
if reply_msg['content']['status'] == u'error':
|
|
293
|
if reply_msg['content']['status'] == u'error':
|
|
218
|
self.abort_queue()
|
|
294
|
self._abort_queue()
|
|
|
|
|
295
|
|
|
|
|
|
296
|
def complete_request(self, ident, parent):
|
|
|
|
|
297
|
comp = self.completer.complete(parent.content.line, parent.content.text)
|
|
|
|
|
298
|
matches = {'matches' : comp, 'status' : 'ok'}
|
|
|
|
|
299
|
completion_msg = self.session.send(self.reply_socket, 'complete_reply',
|
|
|
|
|
300
|
matches, parent, ident)
|
|
|
|
|
301
|
print >> sys.__stdout__, completion_msg
|
|
|
|
|
302
|
|
|
|
|
|
303
|
def object_info_request(self, ident, parent):
|
|
|
|
|
304
|
context = parent['content']['oname'].split('.')
|
|
|
|
|
305
|
object_info = self._object_info(context)
|
|
|
|
|
306
|
msg = self.session.send(self.reply_socket, 'object_info_reply',
|
|
|
|
|
307
|
object_info, parent, ident)
|
|
|
|
|
308
|
print >> sys.__stdout__, msg
|
|
|
|
|
309
|
|
|
|
|
|
310
|
#---------------------------------------------------------------------------
|
|
|
|
|
311
|
# Protected interface
|
|
|
|
|
312
|
#---------------------------------------------------------------------------
|
|
|
|
|
313
|
|
|
|
|
|
314
|
def _abort_queue(self):
|
|
|
|
|
315
|
while True:
|
|
|
|
|
316
|
try:
|
|
|
|
|
317
|
ident = self.reply_socket.recv(zmq.NOBLOCK)
|
|
|
|
|
318
|
except zmq.ZMQError, e:
|
|
|
|
|
319
|
if e.errno == zmq.EAGAIN:
|
|
|
|
|
320
|
break
|
|
|
|
|
321
|
else:
|
|
|
|
|
322
|
assert self.reply_socket.rcvmore(), "Missing message part."
|
|
|
|
|
323
|
msg = self.reply_socket.recv_json()
|
|
|
|
|
324
|
print>>sys.__stdout__, "Aborting:"
|
|
|
|
|
325
|
print>>sys.__stdout__, Message(msg)
|
|
|
|
|
326
|
msg_type = msg['msg_type']
|
|
|
|
|
327
|
reply_type = msg_type.split('_')[0] + '_reply'
|
|
|
|
|
328
|
reply_msg = self.session.msg(reply_type, {'status':'aborted'}, msg)
|
|
|
|
|
329
|
print>>sys.__stdout__, Message(reply_msg)
|
|
|
|
|
330
|
self.reply_socket.send(ident,zmq.SNDMORE)
|
|
|
|
|
331
|
self.reply_socket.send_json(reply_msg)
|
|
|
|
|
332
|
# We need to wait a bit for requests to come in. This can probably
|
|
|
|
|
333
|
# be set shorter for true asynchronous clients.
|
|
|
|
|
334
|
time.sleep(0.1)
|
|
219
|
|
|
335
|
|
|
220
|
def raw_input(self, prompt, ident, parent):
|
|
336
|
def _raw_input(self, prompt, ident, parent):
|
|
221
|
# Flush output before making the request.
|
|
337
|
# Flush output before making the request.
|
|
222
|
sys.stderr.flush()
|
|
338
|
sys.stderr.flush()
|
|
223
|
sys.stdout.flush()
|
|
339
|
sys.stdout.flush()
|
|
@@
-237,25
+353,8
b' class Kernel(object):'
|
|
237
|
value = ''
|
|
353
|
value = ''
|
|
238
|
return value
|
|
354
|
return value
|
|
239
|
|
|
355
|
|
|
240
|
def complete_request(self, ident, parent):
|
|
356
|
def _object_info(self, context):
|
|
241
|
matches = {'matches' : self.complete(parent),
|
|
357
|
symbol, leftover = self._symbol_from_context(context)
|
|
242
|
'status' : 'ok'}
|
|
|
|
|
243
|
completion_msg = self.session.send(self.reply_socket, 'complete_reply',
|
|
|
|
|
244
|
matches, parent, ident)
|
|
|
|
|
245
|
print >> sys.__stdout__, completion_msg
|
|
|
|
|
246
|
|
|
|
|
|
247
|
def complete(self, msg):
|
|
|
|
|
248
|
return self.completer.complete(msg.content.line, msg.content.text)
|
|
|
|
|
249
|
|
|
|
|
|
250
|
def object_info_request(self, ident, parent):
|
|
|
|
|
251
|
context = parent['content']['oname'].split('.')
|
|
|
|
|
252
|
object_info = self.object_info(context)
|
|
|
|
|
253
|
msg = self.session.send(self.reply_socket, 'object_info_reply',
|
|
|
|
|
254
|
object_info, parent, ident)
|
|
|
|
|
255
|
print >> sys.__stdout__, msg
|
|
|
|
|
256
|
|
|
|
|
|
257
|
def object_info(self, context):
|
|
|
|
|
258
|
symbol, leftover = self.symbol_from_context(context)
|
|
|
|
|
259
|
if symbol is not None and not leftover:
|
|
358
|
if symbol is not None and not leftover:
|
|
260
|
doc = getattr(symbol, '__doc__', '')
|
|
359
|
doc = getattr(symbol, '__doc__', '')
|
|
261
|
else:
|
|
360
|
else:
|
|
@@
-263,7
+362,7
b' class Kernel(object):'
|
|
263
|
object_info = dict(docstring = doc)
|
|
362
|
object_info = dict(docstring = doc)
|
|
264
|
return object_info
|
|
363
|
return object_info
|
|
265
|
|
|
364
|
|
|
266
|
def symbol_from_context(self, context):
|
|
365
|
def _symbol_from_context(self, context):
|
|
267
|
if not context:
|
|
366
|
if not context:
|
|
268
|
return None, context
|
|
367
|
return None, context
|
|
269
|
|
|
368
|
|
|
@@
-284,20
+383,6
b' class Kernel(object):'
|
|
284
|
|
|
383
|
|
|
285
|
return symbol, []
|
|
384
|
return symbol, []
|
|
286
|
|
|
385
|
|
|
287
|
def start(self):
|
|
|
|
|
288
|
while True:
|
|
|
|
|
289
|
ident = self.reply_socket.recv()
|
|
|
|
|
290
|
assert self.reply_socket.rcvmore(), "Missing message part."
|
|
|
|
|
291
|
msg = self.reply_socket.recv_json()
|
|
|
|
|
292
|
omsg = Message(msg)
|
|
|
|
|
293
|
print>>sys.__stdout__
|
|
|
|
|
294
|
print>>sys.__stdout__, omsg
|
|
|
|
|
295
|
handler = self.handlers.get(omsg.msg_type, None)
|
|
|
|
|
296
|
if handler is None:
|
|
|
|
|
297
|
print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
|
|
|
|
|
298
|
else:
|
|
|
|
|
299
|
handler(ident, omsg)
|
|
|
|
|
300
|
|
|
|
|
|
301
|
#-----------------------------------------------------------------------------
|
|
386
|
#-----------------------------------------------------------------------------
|
|
302
|
# Kernel main and launch functions
|
|
387
|
# Kernel main and launch functions
|
|
303
|
#-----------------------------------------------------------------------------
|
|
388
|
#-----------------------------------------------------------------------------
|
|
@@
-342,8
+427,8
b' class ExitPollerWindows(Thread):'
|
|
342
|
|
|
427
|
|
|
343
|
|
|
428
|
|
|
344
|
def bind_port(socket, ip, port):
|
|
429
|
def bind_port(socket, ip, port):
|
|
345
|
""" Binds the specified ZMQ socket. If the port is less than zero, a random
|
|
430
|
""" Binds the specified ZMQ socket. If the port is zero, a random port is
|
|
346
|
port is chosen. Returns the port that was bound.
|
|
431
|
chosen. Returns the port that was bound.
|
|
347
|
"""
|
|
432
|
"""
|
|
348
|
connection = 'tcp://%s' % ip
|
|
433
|
connection = 'tcp://%s' % ip
|
|
349
|
if port <= 0:
|
|
434
|
if port <= 0:
|
|
@@
-374,6
+459,12
b' def main():'
|
|
374
|
else:
|
|
459
|
else:
|
|
375
|
parser.add_argument('--parent', action='store_true',
|
|
460
|
parser.add_argument('--parent', action='store_true',
|
|
376
|
help='kill this process if its parent dies')
|
|
461
|
help='kill this process if its parent dies')
|
|
|
|
|
462
|
parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?',
|
|
|
|
|
463
|
const='auto', help = \
|
|
|
|
|
464
|
"Pre-load matplotlib and numpy for interactive use. If GUI is not \
|
|
|
|
|
465
|
given, the GUI backend is matplotlib's, otherwise use one of: \
|
|
|
|
|
466
|
['tk', 'gtk', 'qt', 'wx', 'payload-svg'].")
|
|
|
|
|
467
|
|
|
377
|
namespace = parser.parse_args()
|
|
468
|
namespace = parser.parse_args()
|
|
378
|
|
|
469
|
|
|
379
|
# Create a context, a session, and the kernel sockets.
|
|
470
|
# Create a context, a session, and the kernel sockets.
|
|
@@
-393,14
+484,21
b' def main():'
|
|
393
|
req_port = bind_port(req_socket, namespace.ip, namespace.req)
|
|
484
|
req_port = bind_port(req_socket, namespace.ip, namespace.req)
|
|
394
|
print >>sys.__stdout__, "REQ Channel on port", req_port
|
|
485
|
print >>sys.__stdout__, "REQ Channel on port", req_port
|
|
395
|
|
|
486
|
|
|
|
|
|
487
|
# Create the kernel.
|
|
|
|
|
488
|
kernel = Kernel(session, reply_socket, pub_socket, req_socket)
|
|
|
|
|
489
|
|
|
|
|
|
490
|
# Set up pylab, if necessary.
|
|
|
|
|
491
|
if namespace.pylab:
|
|
|
|
|
492
|
if namespace.pylab == 'auto':
|
|
|
|
|
493
|
kernel.activate_pylab()
|
|
|
|
|
494
|
else:
|
|
|
|
|
495
|
kernel.activate_pylab(namespace.pylab)
|
|
|
|
|
496
|
|
|
396
|
# Redirect input streams and set a display hook.
|
|
497
|
# Redirect input streams and set a display hook.
|
|
397
|
sys.stdout = OutStream(session, pub_socket, u'stdout')
|
|
498
|
sys.stdout = OutStream(session, pub_socket, u'stdout')
|
|
398
|
sys.stderr = OutStream(session, pub_socket, u'stderr')
|
|
499
|
sys.stderr = OutStream(session, pub_socket, u'stderr')
|
|
399
|
sys.displayhook = DisplayHook(session, pub_socket)
|
|
500
|
sys.displayhook = DisplayHook(session, pub_socket)
|
|
400
|
|
|
501
|
|
|
401
|
# Create the kernel.
|
|
|
|
|
402
|
kernel = Kernel(session, reply_socket, pub_socket, req_socket)
|
|
|
|
|
403
|
|
|
|
|
|
404
|
# Configure this kernel/process to die on parent termination, if necessary.
|
|
502
|
# Configure this kernel/process to die on parent termination, if necessary.
|
|
405
|
if namespace.parent:
|
|
503
|
if namespace.parent:
|
|
406
|
if sys.platform == 'win32':
|
|
504
|
if sys.platform == 'win32':
|