Show More
@@ -0,0 +1,213 b'' | |||||
|
1 | #!/usr/bin/env python | |||
|
2 | """An Application for launching a kernel | |||
|
3 | ||||
|
4 | Authors | |||
|
5 | ------- | |||
|
6 | * MinRK | |||
|
7 | """ | |||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | # Copyright (C) 2011 The IPython Development Team | |||
|
10 | # | |||
|
11 | # Distributed under the terms of the BSD License. The full license is in | |||
|
12 | # the file COPYING.txt, distributed as part of this software. | |||
|
13 | #----------------------------------------------------------------------------- | |||
|
14 | ||||
|
15 | #----------------------------------------------------------------------------- | |||
|
16 | # Imports | |||
|
17 | #----------------------------------------------------------------------------- | |||
|
18 | ||||
|
19 | # Standard library imports. | |||
|
20 | import os | |||
|
21 | import sys | |||
|
22 | ||||
|
23 | # System library imports. | |||
|
24 | import zmq | |||
|
25 | ||||
|
26 | # IPython imports. | |||
|
27 | from IPython.core.ultratb import FormattedTB | |||
|
28 | from IPython.core.newapplication import ( | |||
|
29 | BaseIPythonApplication, base_flags, base_aliases | |||
|
30 | ) | |||
|
31 | from IPython.utils import io | |||
|
32 | from IPython.utils.localinterfaces import LOCALHOST | |||
|
33 | from IPython.utils.traitlets import Any, Instance, Dict, Unicode, Int, Bool | |||
|
34 | from IPython.utils.importstring import import_item | |||
|
35 | # local imports | |||
|
36 | from IPython.zmq.heartbeat import Heartbeat | |||
|
37 | from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows | |||
|
38 | from IPython.zmq.session import Session | |||
|
39 | ||||
|
40 | ||||
|
41 | #----------------------------------------------------------------------------- | |||
|
42 | # Flags and Aliases | |||
|
43 | #----------------------------------------------------------------------------- | |||
|
44 | ||||
|
45 | kernel_aliases = dict(base_aliases) | |||
|
46 | kernel_aliases.update({ | |||
|
47 | 'ip' : 'KernelApp.ip', | |||
|
48 | 'hb' : 'KernelApp.hb_port', | |||
|
49 | 'shell' : 'KernelApp.shell_port', | |||
|
50 | 'iopub' : 'KernelApp.iopub_port', | |||
|
51 | 'stdin' : 'KernelApp.stdin_port', | |||
|
52 | 'parent': 'KernelApp.parent', | |||
|
53 | }) | |||
|
54 | if sys.platform.startswith('win'): | |||
|
55 | kernel_aliases['interrupt'] = 'KernelApp.interrupt' | |||
|
56 | ||||
|
57 | kernel_flags = dict(base_flags) | |||
|
58 | kernel_flags.update({ | |||
|
59 | 'no-stdout' : ( | |||
|
60 | {'KernelApp' : {'no_stdout' : True}}, | |||
|
61 | "redirect stdout to the null device"), | |||
|
62 | 'no-stderr' : ( | |||
|
63 | {'KernelApp' : {'no_stderr' : True}}, | |||
|
64 | "redirect stderr to the null device"), | |||
|
65 | }) | |||
|
66 | ||||
|
67 | ||||
|
68 | #----------------------------------------------------------------------------- | |||
|
69 | # Application class for starting a Kernel | |||
|
70 | #----------------------------------------------------------------------------- | |||
|
71 | ||||
|
72 | class KernelApp(BaseIPythonApplication): | |||
|
73 | name='pykernel' | |||
|
74 | aliases = Dict(kernel_aliases) | |||
|
75 | flags = Dict(kernel_flags) | |||
|
76 | ||||
|
77 | # the kernel class, as an importstring | |||
|
78 | kernel_class = Unicode('IPython.zmq.pykernel.Kernel') | |||
|
79 | kernel = Any() | |||
|
80 | poller = Any() # don't restrict this even though current pollers are all Threads | |||
|
81 | heartbeat = Instance(Heartbeat) | |||
|
82 | session = Instance('IPython.zmq.session.Session') | |||
|
83 | ports = Dict() | |||
|
84 | ||||
|
85 | # connection info: | |||
|
86 | ip = Unicode(LOCALHOST, config=True, | |||
|
87 | help="Set the IP or interface on which the kernel will listen.") | |||
|
88 | hb_port = Int(0, config=True, help="set the heartbeat port [default: random]") | |||
|
89 | shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]") | |||
|
90 | iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]") | |||
|
91 | stdin_port = Int(0, config=True, help="set the stdin (XREQ) port [default: random]") | |||
|
92 | ||||
|
93 | # streams, etc. | |||
|
94 | no_stdout = Bool(False, config=True, help="redirect stdout to the null device") | |||
|
95 | no_stderr = Bool(False, config=True, help="redirect stderr to the null device") | |||
|
96 | outstream_class = Unicode('IPython.zmq.iostream.OutStream', config=True, | |||
|
97 | help="The importstring for the OutStream factory") | |||
|
98 | displayhook_class = Unicode('IPython.zmq.displayhook.DisplayHook', config=True, | |||
|
99 | help="The importstring for the DisplayHook factory") | |||
|
100 | ||||
|
101 | # polling | |||
|
102 | parent = Int(0, config=True, | |||
|
103 | help="""kill this process if its parent dies. On Windows, the argument | |||
|
104 | specifies the HANDLE of the parent process, otherwise it is simply boolean. | |||
|
105 | """) | |||
|
106 | interrupt = Int(0, config=True, | |||
|
107 | help="""ONLY USED ON WINDOWS | |||
|
108 | Interrupt this process when the parent is signalled. | |||
|
109 | """) | |||
|
110 | ||||
|
111 | def init_crash_handler(self): | |||
|
112 | # Install minimal exception handling | |||
|
113 | sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', | |||
|
114 | ostream=sys.__stdout__) | |||
|
115 | ||||
|
116 | def init_poller(self): | |||
|
117 | if sys.platform == 'win32': | |||
|
118 | if self.interrupt or self.parent: | |||
|
119 | self.poller = ParentPollerWindows(self.interrupt, self.parent) | |||
|
120 | elif self.parent: | |||
|
121 | self.poller = ParentPollerUnix() | |||
|
122 | ||||
|
123 | def _bind_socket(self, s, port): | |||
|
124 | iface = 'tcp://%s' % self.ip | |||
|
125 | if port <= 0: | |||
|
126 | port = s.bind_to_random_port(iface) | |||
|
127 | else: | |||
|
128 | s.bind(iface + ':%i'%port) | |||
|
129 | return port | |||
|
130 | ||||
|
131 | def init_sockets(self): | |||
|
132 | # Create a context, a session, and the kernel sockets. | |||
|
133 | io.raw_print("Starting the kernel at pid:", os.getpid()) | |||
|
134 | context = zmq.Context.instance() | |||
|
135 | # Uncomment this to try closing the context. | |||
|
136 | # atexit.register(context.term) | |||
|
137 | ||||
|
138 | self.shell_socket = context.socket(zmq.XREP) | |||
|
139 | self.shell_port = self._bind_socket(self.shell_socket, self.shell_port) | |||
|
140 | self.log.debug("shell XREP Channel on port: %i"%self.shell_port) | |||
|
141 | ||||
|
142 | self.iopub_socket = context.socket(zmq.PUB) | |||
|
143 | self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port) | |||
|
144 | self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port) | |||
|
145 | ||||
|
146 | self.stdin_socket = context.socket(zmq.XREQ) | |||
|
147 | self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port) | |||
|
148 | self.log.debug("stdin XREQ Channel on port: %i"%self.stdin_port) | |||
|
149 | ||||
|
150 | self.heartbeat = Heartbeat(context, (self.ip, self.hb_port)) | |||
|
151 | self.hb_port = self.heartbeat.port | |||
|
152 | self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port) | |||
|
153 | ||||
|
154 | # Helper to make it easier to connect to an existing kernel, until we have | |||
|
155 | # single-port connection negotiation fully implemented. | |||
|
156 | self.log.info("To connect another client to this kernel, use:") | |||
|
157 | self.log.info("--external shell={0} iopub={1} stdin={2} hb={3}".format( | |||
|
158 | self.shell_port, self.iopub_port, self.stdin_port, self.hb_port)) | |||
|
159 | ||||
|
160 | ||||
|
161 | self.ports = dict(shell=self.shell_port, iopub=self.iopub_port, | |||
|
162 | stdin=self.stdin_port, hb=self.hb_port) | |||
|
163 | ||||
|
164 | def init_session(self): | |||
|
165 | """create our session object""" | |||
|
166 | self.session = Session(username=u'kernel') | |||
|
167 | ||||
|
168 | def init_io(self): | |||
|
169 | """redirects stdout/stderr, and installs a display hook""" | |||
|
170 | # Re-direct stdout/stderr, if necessary. | |||
|
171 | if self.no_stdout or self.no_stderr: | |||
|
172 | blackhole = file(os.devnull, 'w') | |||
|
173 | if self.no_stdout: | |||
|
174 | sys.stdout = sys.__stdout__ = blackhole | |||
|
175 | if self.no_stderr: | |||
|
176 | sys.stderr = sys.__stderr__ = blackhole | |||
|
177 | ||||
|
178 | # Redirect input streams and set a display hook. | |||
|
179 | ||||
|
180 | if self.outstream_class: | |||
|
181 | outstream_factory = import_item(str(self.outstream_class)) | |||
|
182 | sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout') | |||
|
183 | sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr') | |||
|
184 | if self.displayhook_class: | |||
|
185 | displayhook_factory = import_item(str(self.displayhook_class)) | |||
|
186 | sys.displayhook = displayhook_factory(self.session, self.iopub_socket) | |||
|
187 | ||||
|
188 | def init_kernel(self): | |||
|
189 | """Create the Kernel object itself""" | |||
|
190 | kernel_factory = import_item(str(self.kernel_class)) | |||
|
191 | self.kernel = kernel_factory(config=self.config, session=self.session, | |||
|
192 | shell_socket=self.shell_socket, | |||
|
193 | iopub_socket=self.iopub_socket, | |||
|
194 | stdin_socket=self.stdin_socket, | |||
|
195 | ) | |||
|
196 | self.kernel.record_ports(self.ports) | |||
|
197 | ||||
|
198 | def initialize(self, argv=None): | |||
|
199 | super(KernelApp, self).initialize(argv) | |||
|
200 | self.init_session() | |||
|
201 | self.init_poller() | |||
|
202 | self.init_sockets() | |||
|
203 | self.init_io() | |||
|
204 | self.init_kernel() | |||
|
205 | ||||
|
206 | def start(self): | |||
|
207 | self.heartbeat.start() | |||
|
208 | if self.poller is not None: | |||
|
209 | self.poller.start() | |||
|
210 | try: | |||
|
211 | self.kernel.start() | |||
|
212 | except KeyboardInterrupt: | |||
|
213 | pass |
@@ -0,0 +1,13 b'' | |||||
|
1 | ======================= | |||
|
2 | Log Topic Specification | |||
|
3 | ======================= | |||
|
4 | ||||
|
5 | we use pyzmq to broadcast log events over a PUB socket. Engines, Controllers, etc. can all | |||
|
6 | broadcast. SUB sockets can be used to view the logs, and ZMQ topics are used to help | |||
|
7 | select out what to follow. | |||
|
8 | ||||
|
9 | the PUBHandler object that emits the logs can ascribe topics to log messages. The order is: | |||
|
10 | ||||
|
11 | <root_topic>.<loglevel>.<subtopic>[.<etc>] | |||
|
12 | ||||
|
13 | root_topic is specified as an attribute |
@@ -0,0 +1,111 b'' | |||||
|
1 | """test building messages with streamsession""" | |||
|
2 | ||||
|
3 | #------------------------------------------------------------------------------- | |||
|
4 | # Copyright (C) 2011 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 | import os | |||
|
15 | import uuid | |||
|
16 | import zmq | |||
|
17 | ||||
|
18 | from zmq.tests import BaseZMQTestCase | |||
|
19 | from zmq.eventloop.zmqstream import ZMQStream | |||
|
20 | # from IPython.zmq.tests import SessionTestCase | |||
|
21 | from IPython.parallel import streamsession as ss | |||
|
22 | ||||
|
23 | class SessionTestCase(BaseZMQTestCase): | |||
|
24 | ||||
|
25 | def setUp(self): | |||
|
26 | BaseZMQTestCase.setUp(self) | |||
|
27 | self.session = ss.StreamSession() | |||
|
28 | ||||
|
29 | class TestSession(SessionTestCase): | |||
|
30 | ||||
|
31 | def test_msg(self): | |||
|
32 | """message format""" | |||
|
33 | msg = self.session.msg('execute') | |||
|
34 | thekeys = set('header msg_id parent_header msg_type content'.split()) | |||
|
35 | s = set(msg.keys()) | |||
|
36 | self.assertEquals(s, thekeys) | |||
|
37 | self.assertTrue(isinstance(msg['content'],dict)) | |||
|
38 | self.assertTrue(isinstance(msg['header'],dict)) | |||
|
39 | self.assertTrue(isinstance(msg['parent_header'],dict)) | |||
|
40 | self.assertEquals(msg['msg_type'], 'execute') | |||
|
41 | ||||
|
42 | ||||
|
43 | ||||
|
44 | def test_args(self): | |||
|
45 | """initialization arguments for StreamSession""" | |||
|
46 | s = self.session | |||
|
47 | self.assertTrue(s.pack is ss.default_packer) | |||
|
48 | self.assertTrue(s.unpack is ss.default_unpacker) | |||
|
49 | self.assertEquals(s.username, os.environ.get('USER', 'username')) | |||
|
50 | ||||
|
51 | s = ss.StreamSession() | |||
|
52 | self.assertEquals(s.username, os.environ.get('USER', 'username')) | |||
|
53 | ||||
|
54 | self.assertRaises(TypeError, ss.StreamSession, pack='hi') | |||
|
55 | self.assertRaises(TypeError, ss.StreamSession, unpack='hi') | |||
|
56 | u = str(uuid.uuid4()) | |||
|
57 | s = ss.StreamSession(username='carrot', session=u) | |||
|
58 | self.assertEquals(s.session, u) | |||
|
59 | self.assertEquals(s.username, 'carrot') | |||
|
60 | ||||
|
61 | def test_tracking(self): | |||
|
62 | """test tracking messages""" | |||
|
63 | a,b = self.create_bound_pair(zmq.PAIR, zmq.PAIR) | |||
|
64 | s = self.session | |||
|
65 | stream = ZMQStream(a) | |||
|
66 | msg = s.send(a, 'hello', track=False) | |||
|
67 | self.assertTrue(msg['tracker'] is None) | |||
|
68 | msg = s.send(a, 'hello', track=True) | |||
|
69 | self.assertTrue(isinstance(msg['tracker'], zmq.MessageTracker)) | |||
|
70 | M = zmq.Message(b'hi there', track=True) | |||
|
71 | msg = s.send(a, 'hello', buffers=[M], track=True) | |||
|
72 | t = msg['tracker'] | |||
|
73 | self.assertTrue(isinstance(t, zmq.MessageTracker)) | |||
|
74 | self.assertRaises(zmq.NotDone, t.wait, .1) | |||
|
75 | del M | |||
|
76 | t.wait(1) # this will raise | |||
|
77 | ||||
|
78 | ||||
|
79 | # def test_rekey(self): | |||
|
80 | # """rekeying dict around json str keys""" | |||
|
81 | # d = {'0': uuid.uuid4(), 0:uuid.uuid4()} | |||
|
82 | # self.assertRaises(KeyError, ss.rekey, d) | |||
|
83 | # | |||
|
84 | # d = {'0': uuid.uuid4(), 1:uuid.uuid4(), 'asdf':uuid.uuid4()} | |||
|
85 | # d2 = {0:d['0'],1:d[1],'asdf':d['asdf']} | |||
|
86 | # rd = ss.rekey(d) | |||
|
87 | # self.assertEquals(d2,rd) | |||
|
88 | # | |||
|
89 | # d = {'1.5':uuid.uuid4(),'1':uuid.uuid4()} | |||
|
90 | # d2 = {1.5:d['1.5'],1:d['1']} | |||
|
91 | # rd = ss.rekey(d) | |||
|
92 | # self.assertEquals(d2,rd) | |||
|
93 | # | |||
|
94 | # d = {'1.0':uuid.uuid4(),'1':uuid.uuid4()} | |||
|
95 | # self.assertRaises(KeyError, ss.rekey, d) | |||
|
96 | # | |||
|
97 | def test_unique_msg_ids(self): | |||
|
98 | """test that messages receive unique ids""" | |||
|
99 | ids = set() | |||
|
100 | for i in range(2**12): | |||
|
101 | h = self.session.msg_header('test') | |||
|
102 | msg_id = h['msg_id'] | |||
|
103 | self.assertTrue(msg_id not in ids) | |||
|
104 | ids.add(msg_id) | |||
|
105 | ||||
|
106 | def test_feed_identities(self): | |||
|
107 | """scrub the front for zmq IDENTITIES""" | |||
|
108 | theids = "engine client other".split() | |||
|
109 | content = dict(code='whoda',stuff=object()) | |||
|
110 | themsg = self.session.msg('execute',content=content) | |||
|
111 | pmsg = theids |
@@ -217,9 +217,12 b' def main():' | |||||
217 | if args.pure: |
|
217 | if args.pure: | |
218 | kwargs['ipython']=False |
|
218 | kwargs['ipython']=False | |
219 | else: |
|
219 | else: | |
220 | kwargs['colors']=colors |
|
220 | extra = [] | |
|
221 | if colors: | |||
|
222 | extra.append("colors=%s"%colors) | |||
221 | if args.pylab: |
|
223 | if args.pylab: | |
222 |
|
|
224 | extra.append("pylab=%s"%args.pylab) | |
|
225 | kwargs['extra_arguments'] = extra | |||
223 |
|
226 | |||
224 | kernel_manager.start_kernel(**kwargs) |
|
227 | kernel_manager.start_kernel(**kwargs) | |
225 | kernel_manager.start_channels() |
|
228 | kernel_manager.start_channels() |
@@ -9,159 +9,14 b' import socket' | |||||
9 | from subprocess import Popen, PIPE |
|
9 | from subprocess import Popen, PIPE | |
10 | import sys |
|
10 | import sys | |
11 |
|
11 | |||
12 | # System library imports. |
|
|||
13 | import zmq |
|
|||
14 |
|
||||
15 | # Local imports. |
|
12 | # Local imports. | |
16 | from IPython.core.ultratb import FormattedTB |
|
13 | from parentpoller import ParentPollerWindows | |
17 | from IPython.external.argparse import ArgumentParser |
|
|||
18 | from IPython.utils import io |
|
|||
19 | from IPython.utils.localinterfaces import LOCALHOST |
|
|||
20 | from displayhook import DisplayHook |
|
|||
21 | from heartbeat import Heartbeat |
|
|||
22 | from iostream import OutStream |
|
|||
23 | from parentpoller import ParentPollerUnix, ParentPollerWindows |
|
|||
24 | from session import Session |
|
|||
25 |
|
||||
26 |
|
||||
27 | def bind_port(socket, ip, port): |
|
|||
28 | """ Binds the specified ZMQ socket. If the port is zero, a random port is |
|
|||
29 | chosen. Returns the port that was bound. |
|
|||
30 | """ |
|
|||
31 | connection = 'tcp://%s' % ip |
|
|||
32 | if port <= 0: |
|
|||
33 | port = socket.bind_to_random_port(connection) |
|
|||
34 | else: |
|
|||
35 | connection += ':%i' % port |
|
|||
36 | socket.bind(connection) |
|
|||
37 | return port |
|
|||
38 |
|
||||
39 |
|
||||
40 | def make_argument_parser(): |
|
|||
41 | """ Creates an ArgumentParser for the generic arguments supported by all |
|
|||
42 | kernel entry points. |
|
|||
43 | """ |
|
|||
44 | parser = ArgumentParser() |
|
|||
45 | parser.add_argument('--ip', type=str, default=LOCALHOST, |
|
|||
46 | help='set the kernel\'s IP address [default: local]') |
|
|||
47 | parser.add_argument('--xrep', type=int, metavar='PORT', default=0, |
|
|||
48 | help='set the XREP channel port [default: random]') |
|
|||
49 | parser.add_argument('--pub', type=int, metavar='PORT', default=0, |
|
|||
50 | help='set the PUB channel port [default: random]') |
|
|||
51 | parser.add_argument('--req', type=int, metavar='PORT', default=0, |
|
|||
52 | help='set the REQ channel port [default: random]') |
|
|||
53 | parser.add_argument('--hb', type=int, metavar='PORT', default=0, |
|
|||
54 | help='set the heartbeat port [default: random]') |
|
|||
55 | parser.add_argument('--no-stdout', action='store_true', |
|
|||
56 | help='redirect stdout to the null device') |
|
|||
57 | parser.add_argument('--no-stderr', action='store_true', |
|
|||
58 | help='redirect stderr to the null device') |
|
|||
59 |
|
||||
60 | if sys.platform == 'win32': |
|
|||
61 | parser.add_argument('--interrupt', type=int, metavar='HANDLE', |
|
|||
62 | default=0, help='interrupt this process when ' |
|
|||
63 | 'HANDLE is signaled') |
|
|||
64 | parser.add_argument('--parent', type=int, metavar='HANDLE', |
|
|||
65 | default=0, help='kill this process if the process ' |
|
|||
66 | 'with HANDLE dies') |
|
|||
67 | else: |
|
|||
68 | parser.add_argument('--parent', action='store_true', |
|
|||
69 | help='kill this process if its parent dies') |
|
|||
70 |
|
||||
71 | return parser |
|
|||
72 |
|
||||
73 |
|
||||
74 | def make_kernel(namespace, kernel_factory, |
|
|||
75 | out_stream_factory=None, display_hook_factory=None): |
|
|||
76 | """ Creates a kernel, redirects stdout/stderr, and installs a display hook |
|
|||
77 | and exception handler. |
|
|||
78 | """ |
|
|||
79 | # Re-direct stdout/stderr, if necessary. |
|
|||
80 | if namespace.no_stdout or namespace.no_stderr: |
|
|||
81 | blackhole = file(os.devnull, 'w') |
|
|||
82 | if namespace.no_stdout: |
|
|||
83 | sys.stdout = sys.__stdout__ = blackhole |
|
|||
84 | if namespace.no_stderr: |
|
|||
85 | sys.stderr = sys.__stderr__ = blackhole |
|
|||
86 |
|
||||
87 | # Install minimal exception handling |
|
|||
88 | sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor', |
|
|||
89 | ostream=sys.__stdout__) |
|
|||
90 |
|
14 | |||
91 | # Create a context, a session, and the kernel sockets. |
|
|||
92 | io.raw_print("Starting the kernel at pid:", os.getpid()) |
|
|||
93 | context = zmq.Context() |
|
|||
94 | # Uncomment this to try closing the context. |
|
|||
95 | # atexit.register(context.close) |
|
|||
96 | session = Session(username=u'kernel') |
|
|||
97 |
|
15 | |||
98 | reply_socket = context.socket(zmq.XREP) |
|
|||
99 | xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep) |
|
|||
100 | io.raw_print("XREP Channel on port", xrep_port) |
|
|||
101 |
|
16 | |||
102 | pub_socket = context.socket(zmq.PUB) |
|
17 | def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0, | |
103 | pub_port = bind_port(pub_socket, namespace.ip, namespace.pub) |
|
18 | ip=None, stdin=None, stdout=None, stderr=None, | |
104 | io.raw_print("PUB Channel on port", pub_port) |
|
19 | executable=None, independent=False, extra_arguments=[]): | |
105 |
|
||||
106 | req_socket = context.socket(zmq.XREQ) |
|
|||
107 | req_port = bind_port(req_socket, namespace.ip, namespace.req) |
|
|||
108 | io.raw_print("REQ Channel on port", req_port) |
|
|||
109 |
|
||||
110 | hb = Heartbeat(context, (namespace.ip, namespace.hb)) |
|
|||
111 | hb.start() |
|
|||
112 | hb_port = hb.port |
|
|||
113 | io.raw_print("Heartbeat REP Channel on port", hb_port) |
|
|||
114 |
|
||||
115 | # Helper to make it easier to connect to an existing kernel, until we have |
|
|||
116 | # single-port connection negotiation fully implemented. |
|
|||
117 | io.raw_print("To connect another client to this kernel, use:") |
|
|||
118 | io.raw_print("-e --xreq {0} --sub {1} --rep {2} --hb {3}".format( |
|
|||
119 | xrep_port, pub_port, req_port, hb_port)) |
|
|||
120 |
|
||||
121 | # Redirect input streams and set a display hook. |
|
|||
122 | if out_stream_factory: |
|
|||
123 | sys.stdout = out_stream_factory(session, pub_socket, u'stdout') |
|
|||
124 | sys.stderr = out_stream_factory(session, pub_socket, u'stderr') |
|
|||
125 | if display_hook_factory: |
|
|||
126 | sys.displayhook = display_hook_factory(session, pub_socket) |
|
|||
127 |
|
||||
128 | # Create the kernel. |
|
|||
129 | kernel = kernel_factory(session=session, reply_socket=reply_socket, |
|
|||
130 | pub_socket=pub_socket, req_socket=req_socket) |
|
|||
131 | kernel.record_ports(xrep_port=xrep_port, pub_port=pub_port, |
|
|||
132 | req_port=req_port, hb_port=hb_port) |
|
|||
133 | return kernel |
|
|||
134 |
|
||||
135 |
|
||||
136 | def start_kernel(namespace, kernel): |
|
|||
137 | """ Starts a kernel. |
|
|||
138 | """ |
|
|||
139 | # Configure this kernel process to poll the parent process, if necessary. |
|
|||
140 | if sys.platform == 'win32': |
|
|||
141 | if namespace.interrupt or namespace.parent: |
|
|||
142 | poller = ParentPollerWindows(namespace.interrupt, namespace.parent) |
|
|||
143 | poller.start() |
|
|||
144 | elif namespace.parent: |
|
|||
145 | poller = ParentPollerUnix() |
|
|||
146 | poller.start() |
|
|||
147 |
|
||||
148 | # Start the kernel mainloop. |
|
|||
149 | kernel.start() |
|
|||
150 |
|
||||
151 |
|
||||
152 | def make_default_main(kernel_factory): |
|
|||
153 | """ Creates the simplest possible kernel entry point. |
|
|||
154 | """ |
|
|||
155 | def main(): |
|
|||
156 | namespace = make_argument_parser().parse_args() |
|
|||
157 | kernel = make_kernel(namespace, kernel_factory, OutStream, DisplayHook) |
|
|||
158 | start_kernel(namespace, kernel) |
|
|||
159 | return main |
|
|||
160 |
|
||||
161 |
|
||||
162 | def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0, |
|
|||
163 | stdin=None, stdout=None, stderr=None, |
|
|||
164 | executable=None, independent=False, extra_arguments=[]): |
|
|||
165 | """ Launches a localhost kernel, binding to the specified ports. |
|
20 | """ Launches a localhost kernel, binding to the specified ports. | |
166 |
|
21 | |||
167 | Parameters |
|
22 | Parameters | |
@@ -169,18 +24,21 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
169 | code : str, |
|
24 | code : str, | |
170 | A string of Python code that imports and executes a kernel entry point. |
|
25 | A string of Python code that imports and executes a kernel entry point. | |
171 |
|
26 | |||
172 |
|
|
27 | shell_port : int, optional | |
173 | The port to use for XREP channel. |
|
28 | The port to use for XREP channel. | |
174 |
|
29 | |||
175 | pub_port : int, optional |
|
30 | iopub_port : int, optional | |
176 | The port to use for the SUB channel. |
|
31 | The port to use for the SUB channel. | |
177 |
|
32 | |||
178 |
|
|
33 | stdin_port : int, optional | |
179 | The port to use for the REQ (raw input) channel. |
|
34 | The port to use for the REQ (raw input) channel. | |
180 |
|
35 | |||
181 | hb_port : int, optional |
|
36 | hb_port : int, optional | |
182 | The port to use for the hearbeat REP channel. |
|
37 | The port to use for the hearbeat REP channel. | |
183 |
|
38 | |||
|
39 | ip : str, optional | |||
|
40 | The ip address the kernel will bind to. | |||
|
41 | ||||
184 | stdin, stdout, stderr : optional (default None) |
|
42 | stdin, stdout, stderr : optional (default None) | |
185 | Standards streams, as defined in subprocess.Popen. |
|
43 | Standards streams, as defined in subprocess.Popen. | |
186 |
|
44 | |||
@@ -199,13 +57,13 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
199 | Returns |
|
57 | Returns | |
200 | ------- |
|
58 | ------- | |
201 | A tuple of form: |
|
59 | A tuple of form: | |
202 |
(kernel_process, |
|
60 | (kernel_process, shell_port, iopub_port, stdin_port, hb_port) | |
203 | where kernel_process is a Popen object and the ports are integers. |
|
61 | where kernel_process is a Popen object and the ports are integers. | |
204 | """ |
|
62 | """ | |
205 | # Find open ports as necessary. |
|
63 | # Find open ports as necessary. | |
206 | ports = [] |
|
64 | ports = [] | |
207 |
ports_needed = int( |
|
65 | ports_needed = int(shell_port <= 0) + int(iopub_port <= 0) + \ | |
208 |
int( |
|
66 | int(stdin_port <= 0) + int(hb_port <= 0) | |
209 | for i in xrange(ports_needed): |
|
67 | for i in xrange(ports_needed): | |
210 | sock = socket.socket() |
|
68 | sock = socket.socket() | |
211 | sock.bind(('', 0)) |
|
69 | sock.bind(('', 0)) | |
@@ -214,28 +72,31 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
214 | port = sock.getsockname()[1] |
|
72 | port = sock.getsockname()[1] | |
215 | sock.close() |
|
73 | sock.close() | |
216 | ports[i] = port |
|
74 | ports[i] = port | |
217 |
if |
|
75 | if shell_port <= 0: | |
218 |
|
|
76 | shell_port = ports.pop(0) | |
219 | if pub_port <= 0: |
|
77 | if iopub_port <= 0: | |
220 | pub_port = ports.pop(0) |
|
78 | iopub_port = ports.pop(0) | |
221 |
if |
|
79 | if stdin_port <= 0: | |
222 |
|
|
80 | stdin_port = ports.pop(0) | |
223 | if hb_port <= 0: |
|
81 | if hb_port <= 0: | |
224 | hb_port = ports.pop(0) |
|
82 | hb_port = ports.pop(0) | |
225 |
|
83 | |||
226 | # Build the kernel launch command. |
|
84 | # Build the kernel launch command. | |
227 | if executable is None: |
|
85 | if executable is None: | |
228 | executable = sys.executable |
|
86 | executable = sys.executable | |
229 |
arguments = [ executable, '-c', code, ' |
|
87 | arguments = [ executable, '-c', code, 'shell=%i'%shell_port, | |
230 |
' |
|
88 | 'iopub=%i'%iopub_port, 'stdin=%i'%stdin_port, | |
231 |
' |
|
89 | 'hb=%i'%hb_port | |
|
90 | ] | |||
|
91 | if ip is not None: | |||
|
92 | arguments.append('ip=%s'%ip) | |||
232 | arguments.extend(extra_arguments) |
|
93 | arguments.extend(extra_arguments) | |
233 |
|
94 | |||
234 | # Spawn a kernel. |
|
95 | # Spawn a kernel. | |
235 | if sys.platform == 'win32': |
|
96 | if sys.platform == 'win32': | |
236 | # Create a Win32 event for interrupting the kernel. |
|
97 | # Create a Win32 event for interrupting the kernel. | |
237 | interrupt_event = ParentPollerWindows.create_interrupt_event() |
|
98 | interrupt_event = ParentPollerWindows.create_interrupt_event() | |
238 |
arguments += [ ' |
|
99 | arguments += [ 'interrupt=%i'%interrupt_event ] | |
239 |
|
100 | |||
240 | # If this process in running on pythonw, stdin, stdout, and stderr are |
|
101 | # If this process in running on pythonw, stdin, stdout, and stderr are | |
241 | # invalid. Popen will fail unless they are suitably redirected. We don't |
|
102 | # invalid. Popen will fail unless they are suitably redirected. We don't | |
@@ -273,7 +134,7 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
273 | handle = DuplicateHandle(pid, pid, pid, 0, |
|
134 | handle = DuplicateHandle(pid, pid, pid, 0, | |
274 | True, # Inheritable by new processes. |
|
135 | True, # Inheritable by new processes. | |
275 | DUPLICATE_SAME_ACCESS) |
|
136 | DUPLICATE_SAME_ACCESS) | |
276 |
proc = Popen(arguments + [' |
|
137 | proc = Popen(arguments + ['parent=%i'%int(handle)], | |
277 | stdin=_stdin, stdout=_stdout, stderr=_stderr) |
|
138 | stdin=_stdin, stdout=_stdout, stderr=_stderr) | |
278 |
|
139 | |||
279 | # Attach the interrupt event to the Popen objet so it can be used later. |
|
140 | # Attach the interrupt event to the Popen objet so it can be used later. | |
@@ -293,7 +154,7 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||||
293 | proc = Popen(arguments, preexec_fn=lambda: os.setsid(), |
|
154 | proc = Popen(arguments, preexec_fn=lambda: os.setsid(), | |
294 | stdin=stdin, stdout=stdout, stderr=stderr) |
|
155 | stdin=stdin, stdout=stdout, stderr=stderr) | |
295 | else: |
|
156 | else: | |
296 |
proc = Popen(arguments + [' |
|
157 | proc = Popen(arguments + ['parent=1'], | |
297 | stdin=stdin, stdout=stdout, stderr=stderr) |
|
158 | stdin=stdin, stdout=stdout, stderr=stderr) | |
298 |
|
159 | |||
299 |
return proc, |
|
160 | return proc, shell_port, iopub_port, stdin_port, hb_port |
@@ -27,37 +27,21 b' import zmq' | |||||
27 |
|
27 | |||
28 | # Local imports. |
|
28 | # Local imports. | |
29 | from IPython.config.configurable import Configurable |
|
29 | from IPython.config.configurable import Configurable | |
|
30 | from IPython.config.application import boolean_flag | |||
|
31 | from IPython.core.newapplication import ProfileDir | |||
30 | from IPython.utils import io |
|
32 | from IPython.utils import io | |
31 | from IPython.utils.jsonutil import json_clean |
|
33 | from IPython.utils.jsonutil import json_clean | |
32 | from IPython.lib import pylabtools |
|
34 | from IPython.lib import pylabtools | |
33 |
from IPython.utils.traitlets import |
|
35 | from IPython.utils.traitlets import ( | |
34 | from entry_point import (base_launch_kernel, make_argument_parser, make_kernel, |
|
36 | List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum | |
35 | start_kernel) |
|
37 | ) | |
|
38 | from entry_point import base_launch_kernel | |||
|
39 | from kernelapp import KernelApp, kernel_flags, kernel_aliases | |||
36 | from iostream import OutStream |
|
40 | from iostream import OutStream | |
37 | from session import Session, Message |
|
41 | from session import Session, Message | |
38 | from zmqshell import ZMQInteractiveShell |
|
42 | from zmqshell import ZMQInteractiveShell | |
39 |
|
43 | |||
40 | #----------------------------------------------------------------------------- |
|
|||
41 | # Globals |
|
|||
42 | #----------------------------------------------------------------------------- |
|
|||
43 |
|
||||
44 | # Module-level logger |
|
|||
45 | logger = logging.getLogger(__name__) |
|
|||
46 |
|
44 | |||
47 | # FIXME: this needs to be done more cleanly later, once we have proper |
|
|||
48 | # configuration support. This is a library, so it shouldn't set a stream |
|
|||
49 | # handler, see: |
|
|||
50 | # http://docs.python.org/library/logging.html#configuring-logging-for-a-library |
|
|||
51 | # But this lets us at least do developer debugging for now by manually turning |
|
|||
52 | # it on/off. And once we have full config support, the client entry points |
|
|||
53 | # will select their logging handlers, as well as passing to this library the |
|
|||
54 | # logging level. |
|
|||
55 |
|
||||
56 | if 0: # dbg - set to 1 to actually see the messages. |
|
|||
57 | logger.addHandler(logging.StreamHandler()) |
|
|||
58 | logger.setLevel(logging.DEBUG) |
|
|||
59 |
|
||||
60 | # /FIXME |
|
|||
61 |
|
45 | |||
62 | #----------------------------------------------------------------------------- |
|
46 | #----------------------------------------------------------------------------- | |
63 | # Main kernel class |
|
47 | # Main kernel class | |
@@ -71,9 +55,10 b' class Kernel(Configurable):' | |||||
71 |
|
55 | |||
72 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
56 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
73 | session = Instance(Session) |
|
57 | session = Instance(Session) | |
74 |
|
|
58 | shell_socket = Instance('zmq.Socket') | |
75 | pub_socket = Instance('zmq.Socket') |
|
59 | iopub_socket = Instance('zmq.Socket') | |
76 |
|
|
60 | stdin_socket = Instance('zmq.Socket') | |
|
61 | log = Instance(logging.Logger) | |||
77 |
|
62 | |||
78 | # Private interface |
|
63 | # Private interface | |
79 |
|
64 | |||
@@ -100,7 +85,8 b' class Kernel(Configurable):' | |||||
100 |
|
85 | |||
101 | # This is a dict of port number that the kernel is listening on. It is set |
|
86 | # This is a dict of port number that the kernel is listening on. It is set | |
102 | # by record_ports and used by connect_request. |
|
87 | # by record_ports and used by connect_request. | |
103 |
_recorded_ports = |
|
88 | _recorded_ports = Dict() | |
|
89 | ||||
104 |
|
90 | |||
105 |
|
91 | |||
106 | def __init__(self, **kwargs): |
|
92 | def __init__(self, **kwargs): | |
@@ -111,11 +97,11 b' class Kernel(Configurable):' | |||||
111 | atexit.register(self._at_shutdown) |
|
97 | atexit.register(self._at_shutdown) | |
112 |
|
98 | |||
113 | # Initialize the InteractiveShell subclass |
|
99 | # Initialize the InteractiveShell subclass | |
114 | self.shell = ZMQInteractiveShell.instance() |
|
100 | self.shell = ZMQInteractiveShell.instance(config=self.config) | |
115 | self.shell.displayhook.session = self.session |
|
101 | self.shell.displayhook.session = self.session | |
116 | self.shell.displayhook.pub_socket = self.pub_socket |
|
102 | self.shell.displayhook.pub_socket = self.iopub_socket | |
117 | self.shell.display_pub.session = self.session |
|
103 | self.shell.display_pub.session = self.session | |
118 | self.shell.display_pub.pub_socket = self.pub_socket |
|
104 | self.shell.display_pub.pub_socket = self.iopub_socket | |
119 |
|
105 | |||
120 | # TMP - hack while developing |
|
106 | # TMP - hack while developing | |
121 | self.shell._reply_content = None |
|
107 | self.shell._reply_content = None | |
@@ -131,7 +117,7 b' class Kernel(Configurable):' | |||||
131 | def do_one_iteration(self): |
|
117 | def do_one_iteration(self): | |
132 | """Do one iteration of the kernel's evaluation loop. |
|
118 | """Do one iteration of the kernel's evaluation loop. | |
133 | """ |
|
119 | """ | |
134 |
ident,msg = self.session.recv(self. |
|
120 | ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK) | |
135 | if msg is None: |
|
121 | if msg is None: | |
136 | return |
|
122 | return | |
137 |
|
123 | |||
@@ -143,21 +129,20 b' class Kernel(Configurable):' | |||||
143 | # Print some info about this message and leave a '--->' marker, so it's |
|
129 | # Print some info about this message and leave a '--->' marker, so it's | |
144 | # easier to trace visually the message chain when debugging. Each |
|
130 | # easier to trace visually the message chain when debugging. Each | |
145 | # handler prints its message at the end. |
|
131 | # handler prints its message at the end. | |
146 | # Eventually we'll move these from stdout to a logger. |
|
132 | self.log.debug('\n*** MESSAGE TYPE:'+str(msg['msg_type'])+'***') | |
147 | logger.debug('\n*** MESSAGE TYPE:'+str(msg['msg_type'])+'***') |
|
133 | self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ') | |
148 | logger.debug(' Content: '+str(msg['content'])+'\n --->\n ') |
|
|||
149 |
|
134 | |||
150 | # Find and call actual handler for message |
|
135 | # Find and call actual handler for message | |
151 | handler = self.handlers.get(msg['msg_type'], None) |
|
136 | handler = self.handlers.get(msg['msg_type'], None) | |
152 | if handler is None: |
|
137 | if handler is None: | |
153 |
log |
|
138 | self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg)) | |
154 | else: |
|
139 | else: | |
155 | handler(ident, msg) |
|
140 | handler(ident, msg) | |
156 |
|
141 | |||
157 | # Check whether we should exit, in case the incoming message set the |
|
142 | # Check whether we should exit, in case the incoming message set the | |
158 | # exit flag on |
|
143 | # exit flag on | |
159 | if self.shell.exit_now: |
|
144 | if self.shell.exit_now: | |
160 |
log |
|
145 | self.log.debug('\nExiting IPython kernel...') | |
161 | # We do a normal, clean exit, which allows any actions registered |
|
146 | # We do a normal, clean exit, which allows any actions registered | |
162 | # via atexit (such as history saving) to take place. |
|
147 | # via atexit (such as history saving) to take place. | |
163 | sys.exit(0) |
|
148 | sys.exit(0) | |
@@ -166,26 +151,27 b' class Kernel(Configurable):' | |||||
166 | def start(self): |
|
151 | def start(self): | |
167 | """ Start the kernel main loop. |
|
152 | """ Start the kernel main loop. | |
168 | """ |
|
153 | """ | |
|
154 | poller = zmq.Poller() | |||
|
155 | poller.register(self.shell_socket, zmq.POLLIN) | |||
169 | while True: |
|
156 | while True: | |
170 | try: |
|
157 | try: | |
171 | time.sleep(self._poll_interval) |
|
158 | # scale by extra factor of 10, because there is no | |
|
159 | # reason for this to be anything less than ~ 0.1s | |||
|
160 | # since it is a real poller and will respond | |||
|
161 | # to events immediately | |||
|
162 | poller.poll(10*1000*self._poll_interval) | |||
172 | self.do_one_iteration() |
|
163 | self.do_one_iteration() | |
173 | except KeyboardInterrupt: |
|
164 | except KeyboardInterrupt: | |
174 | # Ctrl-C shouldn't crash the kernel |
|
165 | # Ctrl-C shouldn't crash the kernel | |
175 | io.raw_print("KeyboardInterrupt caught in kernel") |
|
166 | io.raw_print("KeyboardInterrupt caught in kernel") | |
176 |
|
167 | |||
177 |
def record_ports(self, |
|
168 | def record_ports(self, ports): | |
178 | """Record the ports that this kernel is using. |
|
169 | """Record the ports that this kernel is using. | |
179 |
|
170 | |||
180 | The creator of the Kernel instance must call this methods if they |
|
171 | The creator of the Kernel instance must call this methods if they | |
181 | want the :meth:`connect_request` method to return the port numbers. |
|
172 | want the :meth:`connect_request` method to return the port numbers. | |
182 | """ |
|
173 | """ | |
183 |
self._recorded_ports = |
|
174 | self._recorded_ports = ports | |
184 | 'xrep_port' : xrep_port, |
|
|||
185 | 'pub_port' : pub_port, |
|
|||
186 | 'req_port' : req_port, |
|
|||
187 | 'hb_port' : hb_port |
|
|||
188 | } |
|
|||
189 |
|
175 | |||
190 | #--------------------------------------------------------------------------- |
|
176 | #--------------------------------------------------------------------------- | |
191 | # Kernel request handlers |
|
177 | # Kernel request handlers | |
@@ -194,11 +180,11 b' class Kernel(Configurable):' | |||||
194 | def _publish_pyin(self, code, parent): |
|
180 | def _publish_pyin(self, code, parent): | |
195 | """Publish the code request on the pyin stream.""" |
|
181 | """Publish the code request on the pyin stream.""" | |
196 |
|
182 | |||
197 | pyin_msg = self.session.send(self.pub_socket, u'pyin',{u'code':code}, parent=parent) |
|
183 | pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent) | |
198 |
|
184 | |||
199 | def execute_request(self, ident, parent): |
|
185 | def execute_request(self, ident, parent): | |
200 |
|
186 | |||
201 | status_msg = self.session.send(self.pub_socket, |
|
187 | status_msg = self.session.send(self.iopub_socket, | |
202 | u'status', |
|
188 | u'status', | |
203 | {u'execution_state':u'busy'}, |
|
189 | {u'execution_state':u'busy'}, | |
204 | parent=parent |
|
190 | parent=parent | |
@@ -209,8 +195,8 b' class Kernel(Configurable):' | |||||
209 | code = content[u'code'] |
|
195 | code = content[u'code'] | |
210 | silent = content[u'silent'] |
|
196 | silent = content[u'silent'] | |
211 | except: |
|
197 | except: | |
212 |
log |
|
198 | self.log.error("Got bad msg: ") | |
213 |
log |
|
199 | self.log.error(str(Message(parent))) | |
214 | return |
|
200 | return | |
215 |
|
201 | |||
216 | shell = self.shell # we'll need this a lot here |
|
202 | shell = self.shell # we'll need this a lot here | |
@@ -298,14 +284,14 b' class Kernel(Configurable):' | |||||
298 | time.sleep(self._execute_sleep) |
|
284 | time.sleep(self._execute_sleep) | |
299 |
|
285 | |||
300 | # Send the reply. |
|
286 | # Send the reply. | |
301 |
reply_msg = self.session.send(self. |
|
287 | reply_msg = self.session.send(self.shell_socket, u'execute_reply', | |
302 | reply_content, parent, ident=ident) |
|
288 | reply_content, parent, ident=ident) | |
303 |
log |
|
289 | self.log.debug(str(reply_msg)) | |
304 |
|
290 | |||
305 | if reply_msg['content']['status'] == u'error': |
|
291 | if reply_msg['content']['status'] == u'error': | |
306 | self._abort_queue() |
|
292 | self._abort_queue() | |
307 |
|
293 | |||
308 | status_msg = self.session.send(self.pub_socket, |
|
294 | status_msg = self.session.send(self.iopub_socket, | |
309 | u'status', |
|
295 | u'status', | |
310 | {u'execution_state':u'idle'}, |
|
296 | {u'execution_state':u'idle'}, | |
311 | parent=parent |
|
297 | parent=parent | |
@@ -316,17 +302,17 b' class Kernel(Configurable):' | |||||
316 | matches = {'matches' : matches, |
|
302 | matches = {'matches' : matches, | |
317 | 'matched_text' : txt, |
|
303 | 'matched_text' : txt, | |
318 | 'status' : 'ok'} |
|
304 | 'status' : 'ok'} | |
319 |
completion_msg = self.session.send(self. |
|
305 | completion_msg = self.session.send(self.shell_socket, 'complete_reply', | |
320 | matches, parent, ident) |
|
306 | matches, parent, ident) | |
321 |
log |
|
307 | self.log.debug(str(completion_msg)) | |
322 |
|
308 | |||
323 | def object_info_request(self, ident, parent): |
|
309 | def object_info_request(self, ident, parent): | |
324 | object_info = self.shell.object_inspect(parent['content']['oname']) |
|
310 | object_info = self.shell.object_inspect(parent['content']['oname']) | |
325 | # Before we send this object over, we scrub it for JSON usage |
|
311 | # Before we send this object over, we scrub it for JSON usage | |
326 | oinfo = json_clean(object_info) |
|
312 | oinfo = json_clean(object_info) | |
327 |
msg = self.session.send(self. |
|
313 | msg = self.session.send(self.shell_socket, 'object_info_reply', | |
328 | oinfo, parent, ident) |
|
314 | oinfo, parent, ident) | |
329 |
log |
|
315 | self.log.debug(msg) | |
330 |
|
316 | |||
331 | def history_request(self, ident, parent): |
|
317 | def history_request(self, ident, parent): | |
332 | # We need to pull these out, as passing **kwargs doesn't work with |
|
318 | # We need to pull these out, as passing **kwargs doesn't work with | |
@@ -353,18 +339,18 b' class Kernel(Configurable):' | |||||
353 | else: |
|
339 | else: | |
354 | hist = [] |
|
340 | hist = [] | |
355 | content = {'history' : list(hist)} |
|
341 | content = {'history' : list(hist)} | |
356 |
msg = self.session.send(self. |
|
342 | msg = self.session.send(self.shell_socket, 'history_reply', | |
357 | content, parent, ident) |
|
343 | content, parent, ident) | |
358 |
log |
|
344 | self.log.debug(str(msg)) | |
359 |
|
345 | |||
360 | def connect_request(self, ident, parent): |
|
346 | def connect_request(self, ident, parent): | |
361 | if self._recorded_ports is not None: |
|
347 | if self._recorded_ports is not None: | |
362 | content = self._recorded_ports.copy() |
|
348 | content = self._recorded_ports.copy() | |
363 | else: |
|
349 | else: | |
364 | content = {} |
|
350 | content = {} | |
365 |
msg = self.session.send(self. |
|
351 | msg = self.session.send(self.shell_socket, 'connect_reply', | |
366 | content, parent, ident) |
|
352 | content, parent, ident) | |
367 |
log |
|
353 | self.log.debug(msg) | |
368 |
|
354 | |||
369 | def shutdown_request(self, ident, parent): |
|
355 | def shutdown_request(self, ident, parent): | |
370 | self.shell.exit_now = True |
|
356 | self.shell.exit_now = True | |
@@ -377,19 +363,19 b' class Kernel(Configurable):' | |||||
377 |
|
363 | |||
378 | def _abort_queue(self): |
|
364 | def _abort_queue(self): | |
379 | while True: |
|
365 | while True: | |
380 |
ident,msg = self.session.recv(self. |
|
366 | ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK) | |
381 | if msg is None: |
|
367 | if msg is None: | |
382 | break |
|
368 | break | |
383 | else: |
|
369 | else: | |
384 | assert ident is not None, \ |
|
370 | assert ident is not None, \ | |
385 | "Unexpected missing message part." |
|
371 | "Unexpected missing message part." | |
386 |
|
372 | |||
387 |
log |
|
373 | self.log.debug("Aborting:\n"+str(Message(msg))) | |
388 | msg_type = msg['msg_type'] |
|
374 | msg_type = msg['msg_type'] | |
389 | reply_type = msg_type.split('_')[0] + '_reply' |
|
375 | reply_type = msg_type.split('_')[0] + '_reply' | |
390 |
reply_msg = self.session.send(self. |
|
376 | reply_msg = self.session.send(self.shell_socket, reply_type, | |
391 | {'status' : 'aborted'}, msg, ident=ident) |
|
377 | {'status' : 'aborted'}, msg, ident=ident) | |
392 |
log |
|
378 | self.log.debug(reply_msg) | |
393 | # We need to wait a bit for requests to come in. This can probably |
|
379 | # We need to wait a bit for requests to come in. This can probably | |
394 | # be set shorter for true asynchronous clients. |
|
380 | # be set shorter for true asynchronous clients. | |
395 | time.sleep(0.1) |
|
381 | time.sleep(0.1) | |
@@ -401,15 +387,15 b' class Kernel(Configurable):' | |||||
401 |
|
387 | |||
402 | # Send the input request. |
|
388 | # Send the input request. | |
403 | content = dict(prompt=prompt) |
|
389 | content = dict(prompt=prompt) | |
404 |
msg = self.session.send(self. |
|
390 | msg = self.session.send(self.stdin_socket, u'input_request', content, parent) | |
405 |
|
391 | |||
406 | # Await a response. |
|
392 | # Await a response. | |
407 |
ident, reply = self.session.recv(self. |
|
393 | ident, reply = self.session.recv(self.stdin_socket, 0) | |
408 | try: |
|
394 | try: | |
409 | value = reply['content']['value'] |
|
395 | value = reply['content']['value'] | |
410 | except: |
|
396 | except: | |
411 |
log |
|
397 | self.log.error("Got bad raw_input reply: ") | |
412 |
log |
|
398 | self.log.error(str(Message(parent))) | |
413 | value = '' |
|
399 | value = '' | |
414 | return value |
|
400 | return value | |
415 |
|
401 | |||
@@ -461,9 +447,9 b' class Kernel(Configurable):' | |||||
461 | """ |
|
447 | """ | |
462 | # io.rprint("Kernel at_shutdown") # dbg |
|
448 | # io.rprint("Kernel at_shutdown") # dbg | |
463 | if self._shutdown_message is not None: |
|
449 | if self._shutdown_message is not None: | |
464 |
self.session.send(self. |
|
450 | self.session.send(self.shell_socket, self._shutdown_message) | |
465 | self.session.send(self.pub_socket, self._shutdown_message) |
|
451 | self.session.send(self.iopub_socket, self._shutdown_message) | |
466 |
log |
|
452 | self.log.debug(str(self._shutdown_message)) | |
467 | # A very short sleep to give zmq time to flush its message buffers |
|
453 | # A very short sleep to give zmq time to flush its message buffers | |
468 | # before Python truly shuts down. |
|
454 | # before Python truly shuts down. | |
469 | time.sleep(0.01) |
|
455 | time.sleep(0.01) | |
@@ -569,120 +555,191 b' class GTKKernel(Kernel):' | |||||
569 |
|
555 | |||
570 |
|
556 | |||
571 | #----------------------------------------------------------------------------- |
|
557 | #----------------------------------------------------------------------------- | |
572 | # Kernel main and launch functions |
|
558 | # Aliases and Flags for the IPKernelApp | |
573 | #----------------------------------------------------------------------------- |
|
559 | #----------------------------------------------------------------------------- | |
574 |
|
560 | |||
575 | def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0, |
|
561 | flags = dict(kernel_flags) | |
576 | stdin=None, stdout=None, stderr=None, |
|
562 | ||
577 | executable=None, independent=False, pylab=False, colors=None): |
|
563 | addflag = lambda *args: flags.update(boolean_flag(*args)) | |
578 | """Launches a localhost kernel, binding to the specified ports. |
|
564 | addflag('automagic', 'InteractiveShell.automagic', | |
|
565 | """Turn on the auto calling of magic commands. Type %%magic at the | |||
|
566 | IPython prompt for more information.""", | |||
|
567 | 'Turn off the auto calling of magic commands.' | |||
|
568 | ) | |||
|
569 | addflag('banner', 'InteractiveShell.display_banner', | |||
|
570 | "Display a banner upon starting IPython.", | |||
|
571 | "Don't display a banner upon starting IPython." | |||
|
572 | ) | |||
|
573 | addflag('pdb', 'InteractiveShell.pdb', | |||
|
574 | "Enable auto calling the pdb debugger after every exception.", | |||
|
575 | "Disable auto calling the pdb debugger after every exception." | |||
|
576 | ) | |||
|
577 | addflag('pprint', 'PlainTextFormatter.pprint', | |||
|
578 | "Enable auto pretty printing of results.", | |||
|
579 | "Disable auto auto pretty printing of results." | |||
|
580 | ) | |||
|
581 | addflag('color-info', 'InteractiveShell.color_info', | |||
|
582 | """IPython can display information about objects via a set of func- | |||
|
583 | tions, and optionally can use colors for this, syntax highlighting | |||
|
584 | source code and various other elements. However, because this | |||
|
585 | information is passed through a pager (like 'less') and many pagers get | |||
|
586 | confused with color codes, this option is off by default. You can test | |||
|
587 | it and turn it on permanently in your ipython_config.py file if it | |||
|
588 | works for you. Test it and turn it on permanently if it works with | |||
|
589 | your system. The magic function %%color_info allows you to toggle this | |||
|
590 | inter- actively for testing.""", | |||
|
591 | "Disable using colors for info related things." | |||
|
592 | ) | |||
|
593 | addflag('deep-reload', 'InteractiveShell.deep_reload', | |||
|
594 | """Enable deep (recursive) reloading by default. IPython can use the | |||
|
595 | deep_reload module which reloads changes in modules recursively (it | |||
|
596 | replaces the reload() function, so you don't need to change anything to | |||
|
597 | use it). deep_reload() forces a full reload of modules whose code may | |||
|
598 | have changed, which the default reload() function does not. When | |||
|
599 | deep_reload is off, IPython will use the normal reload(), but | |||
|
600 | deep_reload will still be available as dreload(). This fea- ture is off | |||
|
601 | by default [which means that you have both normal reload() and | |||
|
602 | dreload()].""", | |||
|
603 | "Disable deep (recursive) reloading by default." | |||
|
604 | ) | |||
|
605 | addflag('readline', 'InteractiveShell.readline_use', | |||
|
606 | "Enable readline for command line usage.", | |||
|
607 | "Disable readline for command line usage." | |||
|
608 | ) | |||
|
609 | ||||
|
610 | flags['pylab'] = ( | |||
|
611 | {'IPKernelApp' : {'pylab' : 'auto'}}, | |||
|
612 | """Pre-load matplotlib and numpy for interactive use with | |||
|
613 | the default matplotlib backend.""" | |||
|
614 | ) | |||
|
615 | ||||
|
616 | aliases = dict(kernel_aliases) | |||
|
617 | ||||
|
618 | # it's possible we don't want short aliases for *all* of these: | |||
|
619 | aliases.update(dict( | |||
|
620 | autocall='InteractiveShell.autocall', | |||
|
621 | cache_size='InteractiveShell.cache_size', | |||
|
622 | colors='InteractiveShell.colors', | |||
|
623 | logfile='InteractiveShell.logfile', | |||
|
624 | log_append='InteractiveShell.logappend', | |||
|
625 | pi1='InteractiveShell.prompt_in1', | |||
|
626 | pi2='InteractiveShell.prompt_in2', | |||
|
627 | po='InteractiveShell.prompt_out', | |||
|
628 | si='InteractiveShell.separate_in', | |||
|
629 | so='InteractiveShell.separate_out', | |||
|
630 | so2='InteractiveShell.separate_out2', | |||
|
631 | xmode='InteractiveShell.xmode', | |||
|
632 | c='IPKernelApp.code_to_run', | |||
|
633 | ext='IPKernelApp.extra_extension', | |||
|
634 | pylab='IPKernelApp.pylab', | |||
|
635 | )) | |||
579 |
|
636 | |||
580 | Parameters |
|
637 | #----------------------------------------------------------------------------- | |
581 | ---------- |
|
638 | # The IPKernelApp class | |
582 | ip : str, optional |
|
639 | #----------------------------------------------------------------------------- | |
583 | The ip address the kernel will bind to. |
|
|||
584 |
|
||||
585 | xrep_port : int, optional |
|
|||
586 | The port to use for XREP channel. |
|
|||
587 |
|
640 | |||
588 | pub_port : int, optional |
|
641 | class IPKernelApp(KernelApp): | |
589 | The port to use for the SUB channel. |
|
642 | name = 'ipkernel' | |
|
643 | ||||
|
644 | aliases = Dict(aliases) | |||
|
645 | flags = Dict(flags) | |||
|
646 | classes = [Kernel, ZMQInteractiveShell, ProfileDir] | |||
|
647 | # configurables | |||
|
648 | pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'inline', 'auto'], | |||
|
649 | config=True, | |||
|
650 | help="""Pre-load matplotlib and numpy for interactive use, | |||
|
651 | selecting a particular matplotlib backend and loop integration. | |||
|
652 | """ | |||
|
653 | ) | |||
|
654 | extensions = List(Unicode, config=True, | |||
|
655 | help="A list of dotted module names of IPython extensions to load." | |||
|
656 | ) | |||
|
657 | extra_extension = Unicode('', config=True, | |||
|
658 | help="dotted module name of an IPython extension to load." | |||
|
659 | ) | |||
|
660 | def _extra_extension_changed(self, name, old, new): | |||
|
661 | if new: | |||
|
662 | # add to self.extensions | |||
|
663 | self.extensions.append(new) | |||
|
664 | ||||
|
665 | exec_files = List(Unicode, config=True, | |||
|
666 | help="""List of files to run at IPython startup.""" | |||
|
667 | ) | |||
|
668 | file_to_run = Unicode('', config=True, | |||
|
669 | help="""A file to be run""") | |||
|
670 | def _file_to_run_changed(self, name, old, new): | |||
|
671 | self.exec_files.append(new) | |||
|
672 | ||||
|
673 | exec_lines = List(Unicode, config=True, | |||
|
674 | help="""lines of code to run at IPython startup.""" | |||
|
675 | ) | |||
|
676 | code_to_run = Unicode('', config=True, | |||
|
677 | help="Execute the given command string." | |||
|
678 | ) | |||
|
679 | def _code_to_run_changed(self, name, old, new): | |||
|
680 | self.exec_lines.append(new) | |||
|
681 | ||||
|
682 | def init_kernel(self): | |||
|
683 | kernel_factory = Kernel | |||
|
684 | ||||
|
685 | kernel_map = { | |||
|
686 | 'qt' : QtKernel, | |||
|
687 | 'qt4': QtKernel, | |||
|
688 | 'inline': Kernel, | |||
|
689 | 'osx': TkKernel, | |||
|
690 | 'wx' : WxKernel, | |||
|
691 | 'tk' : TkKernel, | |||
|
692 | 'gtk': GTKKernel, | |||
|
693 | } | |||
590 |
|
694 | |||
591 | req_port : int, optional |
|
695 | if self.pylab: | |
592 | The port to use for the REQ (raw input) channel. |
|
696 | key = None if self.pylab == 'auto' else self.pylab | |
|
697 | gui, backend = pylabtools.find_gui_and_backend(key) | |||
|
698 | kernel_factory = kernel_map.get(gui) | |||
|
699 | if kernel_factory is None: | |||
|
700 | raise ValueError('GUI is not supported: %r' % gui) | |||
|
701 | pylabtools.activate_matplotlib(backend) | |||
|
702 | ||||
|
703 | kernel = kernel_factory(config=self.config, session=self.session, | |||
|
704 | shell_socket=self.shell_socket, | |||
|
705 | iopub_socket=self.iopub_socket, | |||
|
706 | stdin_socket=self.stdin_socket, | |||
|
707 | log=self.log | |||
|
708 | ) | |||
|
709 | self.kernel = kernel | |||
|
710 | kernel.record_ports(self.ports) | |||
593 |
|
711 | |||
594 | hb_port : int, optional |
|
712 | if self.pylab: | |
595 | The port to use for the hearbeat REP channel. |
|
713 | pylabtools.import_pylab(kernel.shell.user_ns, backend, | |
|
714 | shell=kernel.shell) | |||
596 |
|
715 | |||
597 | stdin, stdout, stderr : optional (default None) |
|
|||
598 | Standards streams, as defined in subprocess.Popen. |
|
|||
599 |
|
716 | |||
600 | executable : str, optional (default sys.executable) |
|
|||
601 | The Python executable to use for the kernel process. |
|
|||
602 |
|
717 | |||
603 | independent : bool, optional (default False) |
|
718 | #----------------------------------------------------------------------------- | |
604 | If set, the kernel process is guaranteed to survive if this process |
|
719 | # Kernel main and launch functions | |
605 | dies. If not set, an effort is made to ensure that the kernel is killed |
|
720 | #----------------------------------------------------------------------------- | |
606 | when this process dies. Note that in this case it is still good practice |
|
|||
607 | to kill kernels manually before exiting. |
|
|||
608 |
|
721 | |||
609 | pylab : bool or string, optional (default False) |
|
722 | def launch_kernel(*args, **kwargs): | |
610 | If not False, the kernel will be launched with pylab enabled. If a |
|
723 | """Launches a localhost IPython kernel, binding to the specified ports. | |
611 | string is passed, matplotlib will use the specified backend. Otherwise, |
|
|||
612 | matplotlib's default backend will be used. |
|
|||
613 |
|
724 | |||
614 | colors : None or string, optional (default None) |
|
725 | This function simply calls entry_point.base_launch_kernel with the right first | |
615 | If not None, specify the color scheme. One of (NoColor, LightBG, Linux) |
|
726 | command to start an ipkernel. See base_launch_kernel for arguments. | |
616 |
|
727 | |||
617 | Returns |
|
728 | Returns | |
618 | ------- |
|
729 | ------- | |
619 | A tuple of form: |
|
730 | A tuple of form: | |
620 |
(kernel_process, |
|
731 | (kernel_process, shell_port, iopub_port, stdin_port, hb_port) | |
621 | where kernel_process is a Popen object and the ports are integers. |
|
732 | where kernel_process is a Popen object and the ports are integers. | |
622 | """ |
|
733 | """ | |
623 | extra_arguments = [] |
|
|||
624 | if pylab: |
|
|||
625 | extra_arguments.append('--pylab') |
|
|||
626 | if isinstance(pylab, basestring): |
|
|||
627 | extra_arguments.append(pylab) |
|
|||
628 | if ip is not None: |
|
|||
629 | extra_arguments.append('--ip') |
|
|||
630 | if isinstance(ip, basestring): |
|
|||
631 | extra_arguments.append(ip) |
|
|||
632 | if colors is not None: |
|
|||
633 | extra_arguments.append('--colors') |
|
|||
634 | extra_arguments.append(colors) |
|
|||
635 | return base_launch_kernel('from IPython.zmq.ipkernel import main; main()', |
|
734 | return base_launch_kernel('from IPython.zmq.ipkernel import main; main()', | |
636 | xrep_port, pub_port, req_port, hb_port, |
|
735 | *args, **kwargs) | |
637 | stdin, stdout, stderr, |
|
|||
638 | executable, independent, extra_arguments) |
|
|||
639 |
|
736 | |||
640 |
|
737 | |||
641 | def main(): |
|
738 | def main(): | |
642 | """ The IPython kernel main entry point. |
|
739 | """Run a PyKernel as an application""" | |
643 | """ |
|
740 | app = IPKernelApp() | |
644 | parser = make_argument_parser() |
|
741 | app.initialize() | |
645 | parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?', |
|
742 | app.start() | |
646 | const='auto', help = \ |
|
|||
647 | "Pre-load matplotlib and numpy for interactive use. If GUI is not \ |
|
|||
648 | given, the GUI backend is matplotlib's, otherwise use one of: \ |
|
|||
649 | ['tk', 'gtk', 'qt', 'wx', 'osx', 'inline'].") |
|
|||
650 | parser.add_argument('--colors', |
|
|||
651 | type=str, dest='colors', |
|
|||
652 | help="Set the color scheme (NoColor, Linux, and LightBG).", |
|
|||
653 | metavar='ZMQInteractiveShell.colors') |
|
|||
654 | namespace = parser.parse_args() |
|
|||
655 |
|
||||
656 | kernel_class = Kernel |
|
|||
657 |
|
||||
658 | kernel_classes = { |
|
|||
659 | 'qt' : QtKernel, |
|
|||
660 | 'qt4': QtKernel, |
|
|||
661 | 'inline': Kernel, |
|
|||
662 | 'osx': TkKernel, |
|
|||
663 | 'wx' : WxKernel, |
|
|||
664 | 'tk' : TkKernel, |
|
|||
665 | 'gtk': GTKKernel, |
|
|||
666 | } |
|
|||
667 | if namespace.pylab: |
|
|||
668 | if namespace.pylab == 'auto': |
|
|||
669 | gui, backend = pylabtools.find_gui_and_backend() |
|
|||
670 | else: |
|
|||
671 | gui, backend = pylabtools.find_gui_and_backend(namespace.pylab) |
|
|||
672 | kernel_class = kernel_classes.get(gui) |
|
|||
673 | if kernel_class is None: |
|
|||
674 | raise ValueError('GUI is not supported: %r' % gui) |
|
|||
675 | pylabtools.activate_matplotlib(backend) |
|
|||
676 | if namespace.colors: |
|
|||
677 | ZMQInteractiveShell.colors=namespace.colors |
|
|||
678 |
|
||||
679 | kernel = make_kernel(namespace, kernel_class, OutStream) |
|
|||
680 |
|
||||
681 | if namespace.pylab: |
|
|||
682 | pylabtools.import_pylab(kernel.shell.user_ns, backend, |
|
|||
683 | shell=kernel.shell) |
|
|||
684 |
|
||||
685 | start_kernel(namespace, kernel) |
|
|||
686 |
|
743 | |||
687 |
|
744 | |||
688 | if __name__ == '__main__': |
|
745 | if __name__ == '__main__': |
@@ -782,8 +782,8 b' class KernelManager(HasTraits):' | |||||
782 | else: |
|
782 | else: | |
783 | from pykernel import launch_kernel |
|
783 | from pykernel import launch_kernel | |
784 | self.kernel, xrep, pub, req, _hb = launch_kernel( |
|
784 | self.kernel, xrep, pub, req, _hb = launch_kernel( | |
785 |
|
|
785 | shell_port=xreq[1], iopub_port=sub[1], | |
786 |
|
|
786 | stdin_port=rep[1], hb_port=hb[1], **kw) | |
787 | self.xreq_address = (xreq[0], xrep) |
|
787 | self.xreq_address = (xreq[0], xrep) | |
788 | self.sub_address = (sub[0], pub) |
|
788 | self.sub_address = (sub[0], pub) | |
789 | self.rep_address = (rep[0], req) |
|
789 | self.rep_address = (rep[0], req) |
@@ -25,10 +25,11 b' import traceback' | |||||
25 | import zmq |
|
25 | import zmq | |
26 |
|
26 | |||
27 | # Local imports. |
|
27 | # Local imports. | |
28 | from IPython.utils.traitlets import HasTraits, Instance, Float |
|
28 | from IPython.utils.traitlets import HasTraits, Instance, Dict, Float | |
29 | from completer import KernelCompleter |
|
29 | from completer import KernelCompleter | |
30 |
from entry_point import base_launch_kernel |
|
30 | from entry_point import base_launch_kernel | |
31 | from session import Session, Message |
|
31 | from session import Session, Message | |
|
32 | from kernelapp import KernelApp | |||
32 |
|
33 | |||
33 | #----------------------------------------------------------------------------- |
|
34 | #----------------------------------------------------------------------------- | |
34 | # Main kernel class |
|
35 | # Main kernel class | |
@@ -49,16 +50,16 b' class Kernel(HasTraits):' | |||||
49 |
|
50 | |||
50 | # This is a dict of port number that the kernel is listening on. It is set |
|
51 | # This is a dict of port number that the kernel is listening on. It is set | |
51 | # by record_ports and used by connect_request. |
|
52 | # by record_ports and used by connect_request. | |
52 |
_recorded_ports = |
|
53 | _recorded_ports = Dict() | |
53 |
|
54 | |||
54 | #--------------------------------------------------------------------------- |
|
55 | #--------------------------------------------------------------------------- | |
55 | # Kernel interface |
|
56 | # Kernel interface | |
56 | #--------------------------------------------------------------------------- |
|
57 | #--------------------------------------------------------------------------- | |
57 |
|
58 | |||
58 | session = Instance(Session) |
|
59 | session = Instance(Session) | |
59 |
|
|
60 | shell_socket = Instance('zmq.Socket') | |
60 | pub_socket = Instance('zmq.Socket') |
|
61 | iopub_socket = Instance('zmq.Socket') | |
61 |
|
|
62 | stdin_socket = Instance('zmq.Socket') | |
62 |
|
63 | |||
63 | def __init__(self, **kwargs): |
|
64 | def __init__(self, **kwargs): | |
64 | super(Kernel, self).__init__(**kwargs) |
|
65 | super(Kernel, self).__init__(**kwargs) | |
@@ -78,7 +79,7 b' class Kernel(HasTraits):' | |||||
78 | """ Start the kernel main loop. |
|
79 | """ Start the kernel main loop. | |
79 | """ |
|
80 | """ | |
80 | while True: |
|
81 | while True: | |
81 |
ident,msg = self.session.recv(self. |
|
82 | ident,msg = self.session.recv(self.shell_socket,0) | |
82 | assert ident is not None, "Missing message part." |
|
83 | assert ident is not None, "Missing message part." | |
83 | omsg = Message(msg) |
|
84 | omsg = Message(msg) | |
84 | print>>sys.__stdout__ |
|
85 | print>>sys.__stdout__ | |
@@ -89,18 +90,13 b' class Kernel(HasTraits):' | |||||
89 | else: |
|
90 | else: | |
90 | handler(ident, omsg) |
|
91 | handler(ident, omsg) | |
91 |
|
92 | |||
92 |
def record_ports(self, |
|
93 | def record_ports(self, ports): | |
93 | """Record the ports that this kernel is using. |
|
94 | """Record the ports that this kernel is using. | |
94 |
|
95 | |||
95 | The creator of the Kernel instance must call this methods if they |
|
96 | The creator of the Kernel instance must call this methods if they | |
96 | want the :meth:`connect_request` method to return the port numbers. |
|
97 | want the :meth:`connect_request` method to return the port numbers. | |
97 | """ |
|
98 | """ | |
98 |
self._recorded_ports = |
|
99 | self._recorded_ports = ports | |
99 | 'xrep_port' : xrep_port, |
|
|||
100 | 'pub_port' : pub_port, |
|
|||
101 | 'req_port' : req_port, |
|
|||
102 | 'hb_port' : hb_port |
|
|||
103 | } |
|
|||
104 |
|
100 | |||
105 | #--------------------------------------------------------------------------- |
|
101 | #--------------------------------------------------------------------------- | |
106 | # Kernel request handlers |
|
102 | # Kernel request handlers | |
@@ -113,7 +109,7 b' class Kernel(HasTraits):' | |||||
113 | print>>sys.__stderr__, "Got bad msg: " |
|
109 | print>>sys.__stderr__, "Got bad msg: " | |
114 | print>>sys.__stderr__, Message(parent) |
|
110 | print>>sys.__stderr__, Message(parent) | |
115 | return |
|
111 | return | |
116 | pyin_msg = self.session.send(self.pub_socket, u'pyin',{u'code':code}, parent=parent) |
|
112 | pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent) | |
117 |
|
113 | |||
118 | try: |
|
114 | try: | |
119 | comp_code = self.compiler(code, '<zmq-kernel>') |
|
115 | comp_code = self.compiler(code, '<zmq-kernel>') | |
@@ -138,7 +134,7 b' class Kernel(HasTraits):' | |||||
138 | u'ename' : unicode(etype.__name__), |
|
134 | u'ename' : unicode(etype.__name__), | |
139 | u'evalue' : unicode(evalue) |
|
135 | u'evalue' : unicode(evalue) | |
140 | } |
|
136 | } | |
141 | exc_msg = self.session.send(self.pub_socket, u'pyerr', exc_content, parent) |
|
137 | exc_msg = self.session.send(self.iopub_socket, u'pyerr', exc_content, parent) | |
142 | reply_content = exc_content |
|
138 | reply_content = exc_content | |
143 | else: |
|
139 | else: | |
144 | reply_content = { 'status' : 'ok', 'payload' : {} } |
|
140 | reply_content = { 'status' : 'ok', 'payload' : {} } | |
@@ -153,7 +149,7 b' class Kernel(HasTraits):' | |||||
153 | time.sleep(self._execute_sleep) |
|
149 | time.sleep(self._execute_sleep) | |
154 |
|
150 | |||
155 | # Send the reply. |
|
151 | # Send the reply. | |
156 |
reply_msg = self.session.send(self. |
|
152 | reply_msg = self.session.send(self.shell_socket, u'execute_reply', reply_content, parent, ident=ident) | |
157 | print>>sys.__stdout__, Message(reply_msg) |
|
153 | print>>sys.__stdout__, Message(reply_msg) | |
158 | if reply_msg['content']['status'] == u'error': |
|
154 | if reply_msg['content']['status'] == u'error': | |
159 | self._abort_queue() |
|
155 | self._abort_queue() | |
@@ -161,22 +157,22 b' class Kernel(HasTraits):' | |||||
161 | def complete_request(self, ident, parent): |
|
157 | def complete_request(self, ident, parent): | |
162 | matches = {'matches' : self._complete(parent), |
|
158 | matches = {'matches' : self._complete(parent), | |
163 | 'status' : 'ok'} |
|
159 | 'status' : 'ok'} | |
164 |
completion_msg = self.session.send(self. |
|
160 | completion_msg = self.session.send(self.shell_socket, 'complete_reply', | |
165 | matches, parent, ident) |
|
161 | matches, parent, ident) | |
166 | print >> sys.__stdout__, completion_msg |
|
162 | print >> sys.__stdout__, completion_msg | |
167 |
|
163 | |||
168 | def object_info_request(self, ident, parent): |
|
164 | def object_info_request(self, ident, parent): | |
169 | context = parent['content']['oname'].split('.') |
|
165 | context = parent['content']['oname'].split('.') | |
170 | object_info = self._object_info(context) |
|
166 | object_info = self._object_info(context) | |
171 |
msg = self.session.send(self. |
|
167 | msg = self.session.send(self.shell_socket, 'object_info_reply', | |
172 | object_info, parent, ident) |
|
168 | object_info, parent, ident) | |
173 | print >> sys.__stdout__, msg |
|
169 | print >> sys.__stdout__, msg | |
174 |
|
170 | |||
175 | def shutdown_request(self, ident, parent): |
|
171 | def shutdown_request(self, ident, parent): | |
176 | content = dict(parent['content']) |
|
172 | content = dict(parent['content']) | |
177 |
msg = self.session.send(self. |
|
173 | msg = self.session.send(self.shell_socket, 'shutdown_reply', | |
178 | content, parent, ident) |
|
174 | content, parent, ident) | |
179 | msg = self.session.send(self.pub_socket, 'shutdown_reply', |
|
175 | msg = self.session.send(self.iopub_socket, 'shutdown_reply', | |
180 | content, parent, ident) |
|
176 | content, parent, ident) | |
181 | print >> sys.__stdout__, msg |
|
177 | print >> sys.__stdout__, msg | |
182 | time.sleep(0.1) |
|
178 | time.sleep(0.1) | |
@@ -197,7 +193,7 b' class Kernel(HasTraits):' | |||||
197 | print>>sys.__stdout__, Message(msg) |
|
193 | print>>sys.__stdout__, Message(msg) | |
198 | msg_type = msg['msg_type'] |
|
194 | msg_type = msg['msg_type'] | |
199 | reply_type = msg_type.split('_')[0] + '_reply' |
|
195 | reply_type = msg_type.split('_')[0] + '_reply' | |
200 |
reply_msg = self.session.send(self. |
|
196 | reply_msg = self.session.send(self.shell_socket, reply_type, {'status':'aborted'}, msg, ident=ident) | |
201 | print>>sys.__stdout__, Message(reply_msg) |
|
197 | print>>sys.__stdout__, Message(reply_msg) | |
202 | # We need to wait a bit for requests to come in. This can probably |
|
198 | # We need to wait a bit for requests to come in. This can probably | |
203 | # be set shorter for true asynchronous clients. |
|
199 | # be set shorter for true asynchronous clients. | |
@@ -210,10 +206,10 b' class Kernel(HasTraits):' | |||||
210 |
|
206 | |||
211 | # Send the input request. |
|
207 | # Send the input request. | |
212 | content = dict(prompt=prompt) |
|
208 | content = dict(prompt=prompt) | |
213 |
msg = self.session.send(self. |
|
209 | msg = self.session.send(self.stdin_socket, u'input_request', content, parent) | |
214 |
|
210 | |||
215 | # Await a response. |
|
211 | # Await a response. | |
216 |
ident,reply = self.session.recv(self. |
|
212 | ident,reply = self.session.recv(self.stdin_socket, 0) | |
217 | try: |
|
213 | try: | |
218 | value = reply['content']['value'] |
|
214 | value = reply['content']['value'] | |
219 | except: |
|
215 | except: | |
@@ -259,58 +255,26 b' class Kernel(HasTraits):' | |||||
259 | # Kernel main and launch functions |
|
255 | # Kernel main and launch functions | |
260 | #----------------------------------------------------------------------------- |
|
256 | #----------------------------------------------------------------------------- | |
261 |
|
257 | |||
262 | def launch_kernel(ip=None, xrep_port=0, pub_port=0, req_port=0, hb_port=0, |
|
258 | def launch_kernel(*args, **kwargs): | |
263 | stdin=None, stdout=None, stderr=None, |
|
259 | """ Launches a simple Python kernel, binding to the specified ports. | |
264 | executable=None, independent=False): |
|
|||
265 | """ Launches a localhost kernel, binding to the specified ports. |
|
|||
266 |
|
||||
267 | Parameters |
|
|||
268 | ---------- |
|
|||
269 | ip : str, optional |
|
|||
270 | The ip address the kernel will bind to. |
|
|||
271 |
|
260 | |||
272 | xrep_port : int, optional |
|
261 | This function simply calls entry_point.base_launch_kernel with the right first | |
273 | The port to use for XREP channel. |
|
262 | command to start a pykernel. See base_launch_kernel for arguments. | |
274 |
|
||||
275 | pub_port : int, optional |
|
|||
276 | The port to use for the SUB channel. |
|
|||
277 |
|
||||
278 | req_port : int, optional |
|
|||
279 | The port to use for the REQ (raw input) channel. |
|
|||
280 |
|
||||
281 | hb_port : int, optional |
|
|||
282 | The port to use for the hearbeat REP channel. |
|
|||
283 |
|
||||
284 | stdin, stdout, stderr : optional (default None) |
|
|||
285 | Standards streams, as defined in subprocess.Popen. |
|
|||
286 |
|
||||
287 | executable : str, optional (default sys.executable) |
|
|||
288 | The Python executable to use for the kernel process. |
|
|||
289 |
|
||||
290 | independent : bool, optional (default False) |
|
|||
291 | If set, the kernel process is guaranteed to survive if this process |
|
|||
292 | dies. If not set, an effort is made to ensure that the kernel is killed |
|
|||
293 | when this process dies. Note that in this case it is still good practice |
|
|||
294 | to kill kernels manually before exiting. |
|
|||
295 |
|
263 | |||
296 | Returns |
|
264 | Returns | |
297 | ------- |
|
265 | ------- | |
298 | A tuple of form: |
|
266 | A tuple of form: | |
299 | (kernel_process, xrep_port, pub_port, req_port) |
|
267 | (kernel_process, xrep_port, pub_port, req_port, hb_port) | |
300 | where kernel_process is a Popen object and the ports are integers. |
|
268 | where kernel_process is a Popen object and the ports are integers. | |
301 | """ |
|
269 | """ | |
302 | extra_arguments = [] |
|
|||
303 | if ip is not None: |
|
|||
304 | extra_arguments.append('--ip') |
|
|||
305 | if isinstance(ip, basestring): |
|
|||
306 | extra_arguments.append(ip) |
|
|||
307 |
|
||||
308 | return base_launch_kernel('from IPython.zmq.pykernel import main; main()', |
|
270 | return base_launch_kernel('from IPython.zmq.pykernel import main; main()', | |
309 | xrep_port, pub_port, req_port, hb_port, |
|
271 | *args, **kwargs) | |
310 | stdin, stdout, stderr, |
|
|||
311 | executable, independent, extra_arguments) |
|
|||
312 |
|
272 | |||
313 | main = make_default_main(Kernel) |
|
273 | def main(): | |
|
274 | """Run a PyKernel as an application""" | |||
|
275 | app = KernelApp() | |||
|
276 | app.initialize() | |||
|
277 | app.start() | |||
314 |
|
278 | |||
315 | if __name__ == '__main__': |
|
279 | if __name__ == '__main__': | |
316 | main() |
|
280 | main() |
General Comments 0
You need to be logged in to leave comments.
Login now