##// END OF EJS Templates
Implement EmbeddedKernel.
epatters -
Show More
@@ -0,0 +1,43 b''
1 """ Defines a dummy socket implementing (part of) the zmq.Socket interface. """
2
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2012 The IPython Development Team
5 #
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
9
10 #-----------------------------------------------------------------------------
11 # Imports
12 #-----------------------------------------------------------------------------
13
14 # Standard library imports.
15 import Queue
16
17 # System library imports.
18 import zmq
19
20 # Local imports.
21 from IPython.utils.traitlets import HasTraits, Instance, Int
22
23 #-----------------------------------------------------------------------------
24 # Dummy socket class
25 #-----------------------------------------------------------------------------
26
27 class DummySocket(HasTraits):
28 """ A dummy socket implementing (part of) the zmq.Socket interface. """
29
30 queue = Instance(Queue.Queue, ())
31 message_sent = Int(0) # Should be an Event
32
33 #-------------------------------------------------------------------------
34 # zmq.Socket interface
35 #-------------------------------------------------------------------------
36
37 def recv_multipart(self, flags=0, copy=True, track=False):
38 return self.queue.get_nowait()
39
40 def send_multipart(self, msg_parts, flags=0, copy=True, track=False):
41 msg_parts = map(zmq.Message, msg_parts)
42 self.queue.put_nowait(msg_parts)
43 self.message_sent += 1
@@ -11,7 +11,15 b''
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 # Standard library imports
15 from contextlib import contextmanager
16 import logging
17 import sys
18
14 # Local imports.
19 # Local imports.
20 from IPython.embedded.socket import DummySocket
21 from IPython.utils.jsonutil import json_clean
22 from IPython.utils.traitlets import Any, Instance, List
15 from IPython.zmq.ipkernel import Kernel
23 from IPython.zmq.ipkernel import Kernel
16
24
17 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
@@ -19,4 +27,105 b' from IPython.zmq.ipkernel import Kernel'
19 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
20
28
21 class EmbeddedKernel(Kernel):
29 class EmbeddedKernel(Kernel):
22 pass
30
31 #-------------------------------------------------------------------------
32 # EmbeddedKernel interface
33 #-------------------------------------------------------------------------
34
35 frontends = List(
36 Instance('IPython.embedded.kernelmanager.EmbeddedKernelManager'))
37
38 raw_input_str = Any()
39 stdout = Any()
40 stderr = Any()
41
42 #-------------------------------------------------------------------------
43 # Kernel interface
44 #-------------------------------------------------------------------------
45
46 shell_streams = List()
47 control_stream = Any()
48 iopub_socket = Instance(DummySocket, ())
49 stdin_socket = Instance(DummySocket, ())
50
51 def __init__(self, **traits):
52 # When an InteractiveShell is instantiated by our base class, it binds
53 # the current values of sys.stdout and sys.stderr.
54 with self._redirected_io():
55 super(EmbeddedKernel, self).__init__(**traits)
56
57 self.iopub_socket.on_trait_change(self._io_dispatch, 'message_sent')
58
59 def execute_request(self, stream, ident, parent):
60 """ Override for temporary IO redirection. """
61 with self._redirected_io():
62 super(EmbeddedKernel, self).execute_request(stream, ident, parent)
63
64 def start(self):
65 """ Override registration of dispatchers for streams. """
66 self.shell.exit_now = False
67
68 def _abort_queue(self, stream):
69 """ The embedded kernel don't abort requests. """
70 pass
71
72 def _raw_input(self, prompt, ident, parent):
73 # Flush output before making the request.
74 self.raw_input_str = None
75 sys.stderr.flush()
76 sys.stdout.flush()
77
78 # Send the input request.
79 content = json_clean(dict(prompt=prompt))
80 msg = self.session.msg(u'input_request', content, parent)
81 for frontend in self.frontends:
82 if frontend.session.session == parent['header']['session']:
83 frontend.stdin_channel.call_handlers(msg)
84 break
85 else:
86 log.error('No frontend found for raw_input request')
87 return str()
88
89 # Await a response.
90 while self.raw_input_str is None:
91 frontend.stdin_channel.process_events()
92 return self.raw_input_str
93
94 #-------------------------------------------------------------------------
95 # Protected interface
96 #-------------------------------------------------------------------------
97
98 @contextmanager
99 def _redirected_io(self):
100 """ Temporarily redirect IO to the kernel.
101 """
102 sys_stdout, sys_stderr = sys.stdout, sys.stderr
103 sys.stdout, sys.stderr = self.stdout, self.stderr
104 yield
105 sys.stdout, sys.stderr = sys_stdout, sys_stderr
106
107 #------ Trait change handlers --------------------------------------------
108
109 def _io_dispatch(self):
110 """ Called when a message is sent to the IO socket.
111 """
112 ident, msg = self.session.recv(self.iopub_socket, copy=False)
113 for frontend in self.frontends:
114 frontend.sub_channel.call_handlers(msg)
115
116 #------ Trait initializers -----------------------------------------------
117
118 def _log_default(self):
119 return logging.getLogger(__name__)
120
121 def _session_default(self):
122 from IPython.zmq.session import Session
123 return Session(config=self.config)
124
125 def _stdout_default(self):
126 from IPython.zmq.iostream import OutStream
127 return OutStream(self.session, self.iopub_socket, u'stdout')
128
129 def _stderr_default(self):
130 from IPython.zmq.iostream import OutStream
131 return OutStream(self.session, self.iopub_socket, u'stderr')
@@ -13,6 +13,7 b''
13
13
14 # Local imports.
14 # Local imports.
15 from IPython.config.loader import Config
15 from IPython.config.loader import Config
16 from IPython.embedded.socket import DummySocket
16 from IPython.utils.traitlets import HasTraits, Any, Instance, Type
17 from IPython.utils.traitlets import HasTraits, Any, Instance, Type
17
18
18 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
@@ -77,6 +78,10 b' class ShellEmbeddedChannel(EmbeddedChannel):'
77 # flag for whether execute requests should be allowed to call raw_input
78 # flag for whether execute requests should be allowed to call raw_input
78 allow_stdin = True
79 allow_stdin = True
79
80
81 #--------------------------------------------------------------------------
82 # ShellChannel interface
83 #--------------------------------------------------------------------------
84
80 def execute(self, code, silent=False, store_history=True,
85 def execute(self, code, silent=False, store_history=True,
81 user_variables=[], user_expressions={}, allow_stdin=None):
86 user_variables=[], user_expressions={}, allow_stdin=None):
82 """Execute code in the kernel.
87 """Execute code in the kernel.
@@ -115,7 +120,15 b' class ShellEmbeddedChannel(EmbeddedChannel):'
115 -------
120 -------
116 The msg_id of the message sent.
121 The msg_id of the message sent.
117 """
122 """
118 raise NotImplementedError
123 if allow_stdin is None:
124 allow_stdin = self.allow_stdin
125 content = dict(code=code, silent=silent, store_history=store_history,
126 user_variables=user_variables,
127 user_expressions=user_expressions,
128 allow_stdin=allow_stdin)
129 msg = self.manager.session.msg('execute_request', content)
130 self._dispatch_to_kernel(msg)
131 return msg['header']['msg_id']
119
132
120 def complete(self, text, line, cursor_pos, block=None):
133 def complete(self, text, line, cursor_pos, block=None):
121 """Tab complete text in the kernel's namespace.
134 """Tab complete text in the kernel's namespace.
@@ -137,7 +150,10 b' class ShellEmbeddedChannel(EmbeddedChannel):'
137 -------
150 -------
138 The msg_id of the message sent.
151 The msg_id of the message sent.
139 """
152 """
140 raise NotImplementedError
153 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
154 msg = self.manager.session.msg('complete_request', content)
155 self._dispatch_to_kernel(msg)
156 return msg['header']['msg_id']
141
157
142 def object_info(self, oname, detail_level=0):
158 def object_info(self, oname, detail_level=0):
143 """Get metadata information about an object.
159 """Get metadata information about an object.
@@ -153,7 +169,10 b' class ShellEmbeddedChannel(EmbeddedChannel):'
153 -------
169 -------
154 The msg_id of the message sent.
170 The msg_id of the message sent.
155 """
171 """
156 raise NotImplementedError
172 content = dict(oname=oname, detail_level=detail_level)
173 msg = self.manager.session.msg('object_info_request', content)
174 self._dispatch_to_kernel(msg)
175 return msg['header']['msg_id']
157
176
158 def history(self, raw=True, output=False, hist_access_type='range', **kwds):
177 def history(self, raw=True, output=False, hist_access_type='range', **kwds):
159 """Get entries from the history list.
178 """Get entries from the history list.
@@ -187,7 +206,11 b' class ShellEmbeddedChannel(EmbeddedChannel):'
187 -------
206 -------
188 The msg_id of the message sent.
207 The msg_id of the message sent.
189 """
208 """
190 raise NotImplementedError
209 content = dict(raw=raw, output=output,
210 hist_access_type=hist_access_type, **kwds)
211 msg = self.manager.session.msg('history_request', content)
212 self._dispatch_to_kernel(msg)
213 return msg['header']['msg_id']
191
214
192 def shutdown(self, restart=False):
215 def shutdown(self, restart=False):
193 """ Request an immediate kernel shutdown.
216 """ Request an immediate kernel shutdown.
@@ -197,6 +220,25 b' class ShellEmbeddedChannel(EmbeddedChannel):'
197 # FIXME: What to do here?
220 # FIXME: What to do here?
198 raise NotImplementedError('Shutdown not supported for embedded kernel')
221 raise NotImplementedError('Shutdown not supported for embedded kernel')
199
222
223 #--------------------------------------------------------------------------
224 # Protected interface
225 #--------------------------------------------------------------------------
226
227 def _dispatch_to_kernel(self, msg):
228 """ Send a message to the kernel and handle a reply.
229 """
230 kernel = self.manager.kernel
231 if kernel is None:
232 raise RuntimeError('Cannot send request. No kernel exists.')
233
234 stream = DummySocket()
235 self.manager.session.send(stream, msg)
236 msg_parts = stream.recv_multipart()
237 kernel.dispatch_shell(stream, msg_parts)
238
239 idents, reply_msg = self.manager.session.recv(stream, copy=False)
240 self.call_handlers_later(reply_msg)
241
200
242
201 class SubEmbeddedChannel(EmbeddedChannel):
243 class SubEmbeddedChannel(EmbeddedChannel):
202 """The SUB channel which listens for messages that the kernel publishes.
244 """The SUB channel which listens for messages that the kernel publishes.
@@ -216,7 +258,10 b' class StdInEmbeddedChannel(EmbeddedChannel):'
216 def input(self, string):
258 def input(self, string):
217 """ Send a string of raw input to the kernel.
259 """ Send a string of raw input to the kernel.
218 """
260 """
219 raise NotImplementedError
261 kernel = self.manager.kernel
262 if kernel is None:
263 raise RuntimeError('Cannot send input reply. No kernel exists.')
264 kernel.raw_input_str = string
220
265
221
266
222 class HBEmbeddedChannel(EmbeddedChannel):
267 class HBEmbeddedChannel(EmbeddedChannel):
@@ -15,7 +15,7 b''
15 from IPython.config import Configurable
15 from IPython.config import Configurable
16
16
17 from IPython.utils.jsonutil import json_clean
17 from IPython.utils.jsonutil import json_clean
18 from IPython.utils.traitlets import Instance, Dict, CBytes
18 from IPython.utils.traitlets import Any, Instance, Dict, CBytes
19
19
20 from IPython.zmq.serialize import serialize_object
20 from IPython.zmq.serialize import serialize_object
21 from IPython.zmq.session import Session, extract_header
21 from IPython.zmq.session import Session, extract_header
@@ -29,7 +29,7 b' class ZMQDataPublisher(Configurable):'
29
29
30 topic = topic = CBytes(b'datapub')
30 topic = topic = CBytes(b'datapub')
31 session = Instance(Session)
31 session = Instance(Session)
32 pub_socket = Instance('zmq.Socket')
32 pub_socket = Any()
33 parent_header = Dict({})
33 parent_header = Dict({})
34
34
35 def set_parent(self, parent):
35 def set_parent(self, parent):
@@ -3,7 +3,7 b' import sys'
3
3
4 from IPython.core.displayhook import DisplayHook
4 from IPython.core.displayhook import DisplayHook
5 from IPython.utils.jsonutil import encode_images
5 from IPython.utils.jsonutil import encode_images
6 from IPython.utils.traitlets import Instance, Dict
6 from IPython.utils.traitlets import Any, Instance, Dict
7 from session import extract_header, Session
7 from session import extract_header, Session
8
8
9 class ZMQDisplayHook(object):
9 class ZMQDisplayHook(object):
@@ -37,7 +37,7 b' class ZMQShellDisplayHook(DisplayHook):'
37 topic=None
37 topic=None
38
38
39 session = Instance(Session)
39 session = Instance(Session)
40 pub_socket = Instance('zmq.Socket')
40 pub_socket = Any()
41 parent_header = Dict({})
41 parent_header = Dict({})
42
42
43 def set_parent(self, parent):
43 def set_parent(self, parent):
@@ -644,7 +644,6 b' class Kernel(Configurable):'
644 # Protected interface
644 # Protected interface
645 #---------------------------------------------------------------------------
645 #---------------------------------------------------------------------------
646
646
647
648 def _wrap_exception(self, method=None):
647 def _wrap_exception(self, method=None):
649 # import here, because _wrap_exception is only used in parallel,
648 # import here, because _wrap_exception is only used in parallel,
650 # and parallel has higher min pyzmq version
649 # and parallel has higher min pyzmq version
@@ -739,36 +738,6 b' class Kernel(Configurable):'
739 cpos = len(c['line'])
738 cpos = len(c['line'])
740 return self.shell.complete(c['text'], c['line'], cpos)
739 return self.shell.complete(c['text'], c['line'], cpos)
741
740
742 def _object_info(self, context):
743 symbol, leftover = self._symbol_from_context(context)
744 if symbol is not None and not leftover:
745 doc = getattr(symbol, '__doc__', '')
746 else:
747 doc = ''
748 object_info = dict(docstring = doc)
749 return object_info
750
751 def _symbol_from_context(self, context):
752 if not context:
753 return None, context
754
755 base_symbol_string = context[0]
756 symbol = self.shell.user_ns.get(base_symbol_string, None)
757 if symbol is None:
758 symbol = __builtin__.__dict__.get(base_symbol_string, None)
759 if symbol is None:
760 return None, context
761
762 context = context[1:]
763 for i, name in enumerate(context):
764 new_symbol = getattr(symbol, name, None)
765 if new_symbol is None:
766 return symbol, context[i:]
767 else:
768 symbol = new_symbol
769
770 return symbol, []
771
772 def _at_shutdown(self):
741 def _at_shutdown(self):
773 """Actions taken at shutdown by the kernel, called by python's atexit.
742 """Actions taken at shutdown by the kernel, called by python's atexit.
774 """
743 """
@@ -558,11 +558,9 b' class Session(Configurable):'
558 msg : dict
558 msg : dict
559 The constructed message.
559 The constructed message.
560 """
560 """
561
561 if not isinstance(stream, zmq.Socket):
562 if not isinstance(stream, (zmq.Socket, ZMQStream)):
562 # ZMQStreams and dummy sockets do not support tracking.
563 raise TypeError("stream must be Socket or ZMQStream, not %r"%type(stream))
563 track = False
564 elif track and isinstance(stream, ZMQStream):
565 raise TypeError("ZMQStream cannot track messages")
566
564
567 if isinstance(msg_or_type, (Message, dict)):
565 if isinstance(msg_or_type, (Message, dict)):
568 # We got a Message or message dict, not a msg_type so don't
566 # We got a Message or message dict, not a msg_type so don't
@@ -42,7 +42,7 b' from IPython.utils import io, openpy'
42 from IPython.utils.jsonutil import json_clean, encode_images
42 from IPython.utils.jsonutil import json_clean, encode_images
43 from IPython.utils.process import arg_split
43 from IPython.utils.process import arg_split
44 from IPython.utils import py3compat
44 from IPython.utils import py3compat
45 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
45 from IPython.utils.traitlets import Any, Instance, Type, Dict, CBool, CBytes
46 from IPython.utils.warn import warn, error
46 from IPython.utils.warn import warn, error
47 from IPython.zmq.displayhook import ZMQShellDisplayHook
47 from IPython.zmq.displayhook import ZMQShellDisplayHook
48 from IPython.zmq.datapub import ZMQDataPublisher
48 from IPython.zmq.datapub import ZMQDataPublisher
@@ -57,7 +57,7 b' class ZMQDisplayPublisher(DisplayPublisher):'
57 """A display publisher that publishes data using a ZeroMQ PUB socket."""
57 """A display publisher that publishes data using a ZeroMQ PUB socket."""
58
58
59 session = Instance(Session)
59 session = Instance(Session)
60 pub_socket = Instance('zmq.Socket')
60 pub_socket = Any()
61 parent_header = Dict({})
61 parent_header = Dict({})
62 topic = CBytes(b'displaypub')
62 topic = CBytes(b'displaypub')
63
63
General Comments 0
You need to be logged in to leave comments. Login now