Show More
@@ -192,7 +192,7 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
192 | xreq.execute_reply.disconnect(self._handle_execute_reply) |
|
192 | xreq.execute_reply.disconnect(self._handle_execute_reply) | |
193 | xreq.complete_reply.disconnect(self._handle_complete_reply) |
|
193 | xreq.complete_reply.disconnect(self._handle_complete_reply) | |
194 | xreq.object_info_reply.disconnect(self._handle_object_info_reply) |
|
194 | xreq.object_info_reply.disconnect(self._handle_object_info_reply) | |
195 |
rep. |
|
195 | rep.input_requested.disconnect(self._handle_req) | |
196 |
|
196 | |||
197 | # Handle the case where the old kernel manager is still listening. |
|
197 | # Handle the case where the old kernel manager is still listening. | |
198 | if self._kernel_manager.channels_running: |
|
198 | if self._kernel_manager.channels_running: | |
@@ -215,7 +215,7 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
215 | xreq.execute_reply.connect(self._handle_execute_reply) |
|
215 | xreq.execute_reply.connect(self._handle_execute_reply) | |
216 | xreq.complete_reply.connect(self._handle_complete_reply) |
|
216 | xreq.complete_reply.connect(self._handle_complete_reply) | |
217 | xreq.object_info_reply.connect(self._handle_object_info_reply) |
|
217 | xreq.object_info_reply.connect(self._handle_object_info_reply) | |
218 |
rep. |
|
218 | rep.input_requested.connect(self._handle_req) | |
219 |
|
219 | |||
220 | # Handle the case where the kernel manager started channels before |
|
220 | # Handle the case where the kernel manager started channels before | |
221 | # we connected. |
|
221 | # we connected. | |
@@ -325,8 +325,8 b' class FrontendWidget(HistoryConsoleWidget):' | |||||
325 | self.kernel_manager.sub_channel.flush() |
|
325 | self.kernel_manager.sub_channel.flush() | |
326 |
|
326 | |||
327 | def callback(line): |
|
327 | def callback(line): | |
328 |
self.kernel_manager.rep_channel. |
|
328 | self.kernel_manager.rep_channel.input(line) | |
329 | self._readline(callback=callback) |
|
329 | self._readline(req['content']['prompt'], callback=callback) | |
330 |
|
330 | |||
331 | def _handle_sub(self, omsg): |
|
331 | def _handle_sub(self, omsg): | |
332 | if self._hidden: |
|
332 | if self._hidden: |
@@ -98,8 +98,8 b' class QtRepSocketChannel(RepSocketChannel, QtCore.QObject):' | |||||
98 | # Emitted when any message is received. |
|
98 | # Emitted when any message is received. | |
99 | message_received = QtCore.pyqtSignal(object) |
|
99 | message_received = QtCore.pyqtSignal(object) | |
100 |
|
100 | |||
101 |
# Emitted when a |
|
101 | # Emitted when an input request is received. | |
102 |
|
|
102 | input_requested = QtCore.pyqtSignal(object) | |
103 |
|
103 | |||
104 | #--------------------------------------------------------------------------- |
|
104 | #--------------------------------------------------------------------------- | |
105 | # 'object' interface |
|
105 | # 'object' interface | |
@@ -123,8 +123,8 b' class QtRepSocketChannel(RepSocketChannel, QtCore.QObject):' | |||||
123 |
|
123 | |||
124 | # Emit signals for specialized message types. |
|
124 | # Emit signals for specialized message types. | |
125 | msg_type = msg['msg_type'] |
|
125 | msg_type = msg['msg_type'] | |
126 |
if msg_type == ' |
|
126 | if msg_type == 'input_request': | |
127 |
self. |
|
127 | self.input_requested.emit(msg) | |
128 |
|
128 | |||
129 |
|
129 | |||
130 | class QtKernelManager(KernelManager, QtCore.QObject): |
|
130 | class QtKernelManager(KernelManager, QtCore.QObject): |
@@ -37,93 +37,6 b' from completer import KernelCompleter' | |||||
37 | # Kernel and stream classes |
|
37 | # Kernel and stream classes | |
38 | #----------------------------------------------------------------------------- |
|
38 | #----------------------------------------------------------------------------- | |
39 |
|
39 | |||
40 | class InStream(object): |
|
|||
41 | """ A file like object that reads from a 0MQ XREQ socket.""" |
|
|||
42 |
|
||||
43 | def __init__(self, session, socket): |
|
|||
44 | self.session = session |
|
|||
45 | self.socket = socket |
|
|||
46 |
|
||||
47 | def close(self): |
|
|||
48 | self.socket = None |
|
|||
49 |
|
||||
50 | def flush(self): |
|
|||
51 | if self.socket is None: |
|
|||
52 | raise ValueError('I/O operation on closed file') |
|
|||
53 |
|
||||
54 | def isatty(self): |
|
|||
55 | return False |
|
|||
56 |
|
||||
57 | def next(self): |
|
|||
58 | raise IOError('Seek not supported.') |
|
|||
59 |
|
||||
60 | def read(self, size=-1): |
|
|||
61 | # FIXME: Do we want another request for this? |
|
|||
62 | string = '\n'.join(self.readlines()) |
|
|||
63 | return self._truncate(string, size) |
|
|||
64 |
|
||||
65 | def readline(self, size=-1): |
|
|||
66 | if self.socket is None: |
|
|||
67 | raise ValueError('I/O operation on closed file') |
|
|||
68 | else: |
|
|||
69 | content = dict(size=size) |
|
|||
70 | msg = self.session.msg('readline_request', content=content) |
|
|||
71 | reply = self._request(msg) |
|
|||
72 | line = reply['content']['line'] |
|
|||
73 | return self._truncate(line, size) |
|
|||
74 |
|
||||
75 | def readlines(self, sizehint=-1): |
|
|||
76 | # Sizehint is ignored, as is permitted. |
|
|||
77 | if self.socket is None: |
|
|||
78 | raise ValueError('I/O operation on closed file') |
|
|||
79 | else: |
|
|||
80 | lines = [] |
|
|||
81 | while True: |
|
|||
82 | line = self.readline() |
|
|||
83 | if line: |
|
|||
84 | lines.append(line) |
|
|||
85 | else: |
|
|||
86 | break |
|
|||
87 | return lines |
|
|||
88 |
|
||||
89 | def seek(self, offset, whence=None): |
|
|||
90 | raise IOError('Seek not supported.') |
|
|||
91 |
|
||||
92 | def write(self, string): |
|
|||
93 | raise IOError('Write not supported on a read only stream.') |
|
|||
94 |
|
||||
95 | def writelines(self, sequence): |
|
|||
96 | raise IOError('Write not supported on a read only stream.') |
|
|||
97 |
|
||||
98 | def _request(self, msg): |
|
|||
99 | # Flush output before making the request. This ensures, for example, |
|
|||
100 | # that raw_input(prompt) actually gets a prompt written. |
|
|||
101 | sys.stderr.flush() |
|
|||
102 | sys.stdout.flush() |
|
|||
103 |
|
||||
104 | self.socket.send_json(msg) |
|
|||
105 | while True: |
|
|||
106 | try: |
|
|||
107 | reply = self.socket.recv_json(zmq.NOBLOCK) |
|
|||
108 | except zmq.ZMQError, e: |
|
|||
109 | if e.errno == zmq.EAGAIN: |
|
|||
110 | pass |
|
|||
111 | else: |
|
|||
112 | raise |
|
|||
113 | else: |
|
|||
114 | break |
|
|||
115 | return reply |
|
|||
116 |
|
||||
117 | def _truncate(self, string, size): |
|
|||
118 | if size >= 0: |
|
|||
119 | if isinstance(string, str): |
|
|||
120 | return string[:size] |
|
|||
121 | elif isinstance(string, unicode): |
|
|||
122 | encoded = string.encode('utf-8')[:size] |
|
|||
123 | return encoded.decode('utf-8', 'ignore') |
|
|||
124 | return string |
|
|||
125 |
|
||||
126 |
|
||||
127 | class OutStream(object): |
|
40 | class OutStream(object): | |
128 | """A file like object that publishes the stream to a 0MQ PUB socket.""" |
|
41 | """A file like object that publishes the stream to a 0MQ PUB socket.""" | |
129 |
|
42 | |||
@@ -215,10 +128,11 b' class DisplayHook(object):' | |||||
215 |
|
128 | |||
216 | class Kernel(object): |
|
129 | class Kernel(object): | |
217 |
|
130 | |||
218 | def __init__(self, session, reply_socket, pub_socket): |
|
131 | def __init__(self, session, reply_socket, pub_socket, req_socket): | |
219 | self.session = session |
|
132 | self.session = session | |
220 | self.reply_socket = reply_socket |
|
133 | self.reply_socket = reply_socket | |
221 | self.pub_socket = pub_socket |
|
134 | self.pub_socket = pub_socket | |
|
135 | self.req_socket = req_socket | |||
222 | self.user_ns = {} |
|
136 | self.user_ns = {} | |
223 | self.history = [] |
|
137 | self.history = [] | |
224 | self.compiler = CommandCompiler() |
|
138 | self.compiler = CommandCompiler() | |
@@ -265,7 +179,15 b' class Kernel(object):' | |||||
265 |
|
179 | |||
266 | try: |
|
180 | try: | |
267 | comp_code = self.compiler(code, '<zmq-kernel>') |
|
181 | comp_code = self.compiler(code, '<zmq-kernel>') | |
|
182 | ||||
|
183 | # Replace raw_input. Note that is not sufficient to replace | |||
|
184 | # raw_input in the user namespace. | |||
|
185 | raw_input = lambda prompt='': self.raw_input(prompt, ident, parent) | |||
|
186 | __builtin__.raw_input = raw_input | |||
|
187 | ||||
|
188 | # Configure the display hook. | |||
268 | sys.displayhook.set_parent(parent) |
|
189 | sys.displayhook.set_parent(parent) | |
|
190 | ||||
269 | exec comp_code in self.user_ns, self.user_ns |
|
191 | exec comp_code in self.user_ns, self.user_ns | |
270 | except: |
|
192 | except: | |
271 | result = u'error' |
|
193 | result = u'error' | |
@@ -295,6 +217,26 b' class Kernel(object):' | |||||
295 | if reply_msg['content']['status'] == u'error': |
|
217 | if reply_msg['content']['status'] == u'error': | |
296 | self.abort_queue() |
|
218 | self.abort_queue() | |
297 |
|
219 | |||
|
220 | def raw_input(self, prompt, ident, parent): | |||
|
221 | # Flush output before making the request. | |||
|
222 | sys.stderr.flush() | |||
|
223 | sys.stdout.flush() | |||
|
224 | ||||
|
225 | # Send the input request. | |||
|
226 | content = dict(prompt=prompt) | |||
|
227 | msg = self.session.msg(u'input_request', content, parent) | |||
|
228 | self.req_socket.send_json(msg) | |||
|
229 | ||||
|
230 | # Await a response. | |||
|
231 | reply = self.req_socket.recv_json() | |||
|
232 | try: | |||
|
233 | value = reply['content']['value'] | |||
|
234 | except: | |||
|
235 | print>>sys.__stderr__, "Got bad raw_input reply: " | |||
|
236 | print>>sys.__stderr__, Message(parent) | |||
|
237 | value = '' | |||
|
238 | return value | |||
|
239 | ||||
298 | def complete_request(self, ident, parent): |
|
240 | def complete_request(self, ident, parent): | |
299 | matches = {'matches' : self.complete(parent), |
|
241 | matches = {'matches' : self.complete(parent), | |
300 | 'status' : 'ok'} |
|
242 | 'status' : 'ok'} | |
@@ -345,7 +287,7 b' class Kernel(object):' | |||||
345 | def start(self): |
|
287 | def start(self): | |
346 | while True: |
|
288 | while True: | |
347 | ident = self.reply_socket.recv() |
|
289 | ident = self.reply_socket.recv() | |
348 |
assert self.reply_socket.rcvmore(), " |
|
290 | assert self.reply_socket.rcvmore(), "Missing message part." | |
349 | msg = self.reply_socket.recv_json() |
|
291 | msg = self.reply_socket.recv_json() | |
350 | omsg = Message(msg) |
|
292 | omsg = Message(msg) | |
351 | print>>sys.__stdout__ |
|
293 | print>>sys.__stdout__ | |
@@ -362,7 +304,7 b' class Kernel(object):' | |||||
362 |
|
304 | |||
363 | class ExitPollerUnix(Thread): |
|
305 | class ExitPollerUnix(Thread): | |
364 | """ A Unix-specific daemon thread that terminates the program immediately |
|
306 | """ A Unix-specific daemon thread that terminates the program immediately | |
365 |
when th |
|
307 | when the parent process no longer exists. | |
366 | """ |
|
308 | """ | |
367 |
|
309 | |||
368 | def __init__(self): |
|
310 | def __init__(self): | |
@@ -452,13 +394,12 b' def main():' | |||||
452 | print >>sys.__stdout__, "REQ Channel on port", req_port |
|
394 | print >>sys.__stdout__, "REQ Channel on port", req_port | |
453 |
|
395 | |||
454 | # Redirect input streams and set a display hook. |
|
396 | # Redirect input streams and set a display hook. | |
455 | sys.stdin = InStream(session, req_socket) |
|
|||
456 | sys.stdout = OutStream(session, pub_socket, u'stdout') |
|
397 | sys.stdout = OutStream(session, pub_socket, u'stdout') | |
457 | sys.stderr = OutStream(session, pub_socket, u'stderr') |
|
398 | sys.stderr = OutStream(session, pub_socket, u'stderr') | |
458 | sys.displayhook = DisplayHook(session, pub_socket) |
|
399 | sys.displayhook = DisplayHook(session, pub_socket) | |
459 |
|
400 | |||
460 | # Create the kernel. |
|
401 | # Create the kernel. | |
461 | kernel = Kernel(session, reply_socket, pub_socket) |
|
402 | kernel = Kernel(session, reply_socket, pub_socket, req_socket) | |
462 |
|
403 | |||
463 | # Configure this kernel/process to die on parent termination, if necessary. |
|
404 | # Configure this kernel/process to die on parent termination, if necessary. | |
464 | if namespace.parent: |
|
405 | if namespace.parent: |
@@ -368,16 +368,10 b' class RepSocketChannel(ZmqSocketChannel):' | |||||
368 | """ |
|
368 | """ | |
369 | raise NotImplementedError('call_handlers must be defined in a subclass.') |
|
369 | raise NotImplementedError('call_handlers must be defined in a subclass.') | |
370 |
|
370 | |||
371 |
def |
|
371 | def input(self, string): | |
372 |
""" |
|
372 | """Send a string of raw input to the kernel.""" | |
373 |
|
373 | content = dict(value=string) | ||
374 | Parameters |
|
374 | msg = self.session.msg('input_reply', content) | |
375 | ---------- |
|
|||
376 | line : str |
|
|||
377 | The line of the input. |
|
|||
378 | """ |
|
|||
379 | content = dict(line=line) |
|
|||
380 | msg = self.session.msg('readline_reply', content) |
|
|||
381 | self._queue_reply(msg) |
|
375 | self._queue_reply(msg) | |
382 |
|
376 | |||
383 | def _handle_events(self, socket, events): |
|
377 | def _handle_events(self, socket, events): | |
@@ -432,13 +426,15 b' class KernelManager(HasTraits):' | |||||
432 | # The Session to use for communication with the kernel. |
|
426 | # The Session to use for communication with the kernel. | |
433 | session = Instance(Session) |
|
427 | session = Instance(Session) | |
434 |
|
428 | |||
|
429 | # The kernel process with which the KernelManager is communicating. | |||
|
430 | kernel = Instance(Popen) | |||
|
431 | ||||
435 | # The classes to use for the various channels. |
|
432 | # The classes to use for the various channels. | |
436 | xreq_channel_class = Type(XReqSocketChannel) |
|
433 | xreq_channel_class = Type(XReqSocketChannel) | |
437 | sub_channel_class = Type(SubSocketChannel) |
|
434 | sub_channel_class = Type(SubSocketChannel) | |
438 | rep_channel_class = Type(RepSocketChannel) |
|
435 | rep_channel_class = Type(RepSocketChannel) | |
439 |
|
436 | |||
440 | # Protected traits. |
|
437 | # Protected traits. | |
441 | _kernel = Instance(Popen) |
|
|||
442 | _xreq_address = Any |
|
438 | _xreq_address = Any | |
443 | _sub_address = Any |
|
439 | _sub_address = Any | |
444 | _rep_address = Any |
|
440 | _rep_address = Any | |
@@ -504,9 +500,8 b' class KernelManager(HasTraits):' | |||||
504 | "Make sure that the '*_address' attributes are " |
|
500 | "Make sure that the '*_address' attributes are " | |
505 | "configured properly.") |
|
501 | "configured properly.") | |
506 |
|
502 | |||
507 | kernel, xrep, pub, req = launch_kernel( |
|
503 | self.kernel, xrep, pub, req = launch_kernel( | |
508 | xrep_port=xreq[1], pub_port=sub[1], req_port=rep[1]) |
|
504 | xrep_port=xreq[1], pub_port=sub[1], req_port=rep[1]) | |
509 | self._kernel = kernel |
|
|||
510 | self._xreq_address = (LOCALHOST, xrep) |
|
505 | self._xreq_address = (LOCALHOST, xrep) | |
511 | self._sub_address = (LOCALHOST, pub) |
|
506 | self._sub_address = (LOCALHOST, pub) | |
512 | self._rep_address = (LOCALHOST, req) |
|
507 | self._rep_address = (LOCALHOST, req) | |
@@ -515,31 +510,29 b' class KernelManager(HasTraits):' | |||||
515 | def has_kernel(self): |
|
510 | def has_kernel(self): | |
516 | """Returns whether a kernel process has been specified for the kernel |
|
511 | """Returns whether a kernel process has been specified for the kernel | |
517 | manager. |
|
512 | manager. | |
518 |
|
||||
519 | A kernel process can be set via 'start_kernel' or 'set_kernel'. |
|
|||
520 | """ |
|
513 | """ | |
521 |
return self. |
|
514 | return self.kernel is not None | |
522 |
|
515 | |||
523 | def kill_kernel(self): |
|
516 | def kill_kernel(self): | |
524 | """ Kill the running kernel. """ |
|
517 | """ Kill the running kernel. """ | |
525 |
if self. |
|
518 | if self.kernel is not None: | |
526 |
self. |
|
519 | self.kernel.kill() | |
527 |
self. |
|
520 | self.kernel = None | |
528 | else: |
|
521 | else: | |
529 | raise RuntimeError("Cannot kill kernel. No kernel is running!") |
|
522 | raise RuntimeError("Cannot kill kernel. No kernel is running!") | |
530 |
|
523 | |||
531 | def signal_kernel(self, signum): |
|
524 | def signal_kernel(self, signum): | |
532 | """ Sends a signal to the kernel. """ |
|
525 | """ Sends a signal to the kernel. """ | |
533 |
if self. |
|
526 | if self.kernel is not None: | |
534 |
self. |
|
527 | self.kernel.send_signal(signum) | |
535 | else: |
|
528 | else: | |
536 | raise RuntimeError("Cannot signal kernel. No kernel is running!") |
|
529 | raise RuntimeError("Cannot signal kernel. No kernel is running!") | |
537 |
|
530 | |||
538 | @property |
|
531 | @property | |
539 | def is_alive(self): |
|
532 | def is_alive(self): | |
540 | """Is the kernel process still running?""" |
|
533 | """Is the kernel process still running?""" | |
541 |
if self. |
|
534 | if self.kernel is not None: | |
542 |
if self. |
|
535 | if self.kernel.poll() is None: | |
543 | return True |
|
536 | return True | |
544 | else: |
|
537 | else: | |
545 | return False |
|
538 | return False |
General Comments 0
You need to be logged in to leave comments.
Login now