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 | 217 | if args.pure: |
|
218 | 218 | kwargs['ipython']=False |
|
219 | 219 | else: |
|
220 | kwargs['colors']=colors | |
|
220 | extra = [] | |
|
221 | if colors: | |
|
222 | extra.append("colors=%s"%colors) | |
|
221 | 223 | if args.pylab: |
|
222 |
|
|
|
224 | extra.append("pylab=%s"%args.pylab) | |
|
225 | kwargs['extra_arguments'] = extra | |
|
223 | 226 | |
|
224 | 227 | kernel_manager.start_kernel(**kwargs) |
|
225 | 228 | kernel_manager.start_channels() |
@@ -9,158 +9,13 b' import socket' | |||
|
9 | 9 | from subprocess import Popen, PIPE |
|
10 | 10 | import sys |
|
11 | 11 | |
|
12 | # System library imports. | |
|
13 | import zmq | |
|
14 | ||
|
15 | 12 | # Local imports. |
|
16 | from IPython.core.ultratb import FormattedTB | |
|
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__) | |
|
13 | from parentpoller import ParentPollerWindows | |
|
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) | |
|
103 | pub_port = bind_port(pub_socket, namespace.ip, namespace.pub) | |
|
104 | io.raw_print("PUB Channel on port", pub_port) | |
|
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, | |
|
17 | def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0, | |
|
18 | ip=None, stdin=None, stdout=None, stderr=None, | |
|
164 | 19 | executable=None, independent=False, extra_arguments=[]): |
|
165 | 20 | """ Launches a localhost kernel, binding to the specified ports. |
|
166 | 21 | |
@@ -169,18 +24,21 b' def base_launch_kernel(code, xrep_port=0, pub_port=0, req_port=0, hb_port=0,' | |||
|
169 | 24 | code : str, |
|
170 | 25 | A string of Python code that imports and executes a kernel entry point. |
|
171 | 26 | |
|
172 |
|
|
|
27 | shell_port : int, optional | |
|
173 | 28 | The port to use for XREP channel. |
|
174 | 29 | |
|
175 | pub_port : int, optional | |
|
30 | iopub_port : int, optional | |
|
176 | 31 | The port to use for the SUB channel. |
|
177 | 32 | |
|
178 |
|
|
|
33 | stdin_port : int, optional | |
|
179 | 34 | The port to use for the REQ (raw input) channel. |
|
180 | 35 | |
|
181 | 36 | hb_port : int, optional |
|
182 | 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 | 42 | stdin, stdout, stderr : optional (default None) |
|
185 | 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 | 57 | Returns |
|
200 | 58 | ------- |
|
201 | 59 | A tuple of form: |
|
202 |
(kernel_process, |
|
|
60 | (kernel_process, shell_port, iopub_port, stdin_port, hb_port) | |
|
203 | 61 | where kernel_process is a Popen object and the ports are integers. |
|
204 | 62 | """ |
|
205 | 63 | # Find open ports as necessary. |
|
206 | 64 | ports = [] |
|
207 |
ports_needed = int( |
|
|
208 |
int( |
|
|
65 | ports_needed = int(shell_port <= 0) + int(iopub_port <= 0) + \ | |
|
66 | int(stdin_port <= 0) + int(hb_port <= 0) | |
|
209 | 67 | for i in xrange(ports_needed): |
|
210 | 68 | sock = socket.socket() |
|
211 | 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 | 72 | port = sock.getsockname()[1] |
|
215 | 73 | sock.close() |
|
216 | 74 | ports[i] = port |
|
217 |
if |
|
|
218 |
|
|
|
219 | if pub_port <= 0: | |
|
220 | pub_port = ports.pop(0) | |
|
221 |
if |
|
|
222 |
|
|
|
75 | if shell_port <= 0: | |
|
76 | shell_port = ports.pop(0) | |
|
77 | if iopub_port <= 0: | |
|
78 | iopub_port = ports.pop(0) | |
|
79 | if stdin_port <= 0: | |
|
80 | stdin_port = ports.pop(0) | |
|
223 | 81 | if hb_port <= 0: |
|
224 | 82 | hb_port = ports.pop(0) |
|
225 | 83 | |
|
226 | 84 | # Build the kernel launch command. |
|
227 | 85 | if executable is None: |
|
228 | 86 | executable = sys.executable |
|
229 |
arguments = [ executable, '-c', code, ' |
|
|
230 |
' |
|
|
231 |
' |
|
|
87 | arguments = [ executable, '-c', code, 'shell=%i'%shell_port, | |
|
88 | 'iopub=%i'%iopub_port, 'stdin=%i'%stdin_port, | |
|
89 | 'hb=%i'%hb_port | |
|
90 | ] | |
|
91 | if ip is not None: | |
|
92 | arguments.append('ip=%s'%ip) | |
|
232 | 93 | arguments.extend(extra_arguments) |
|
233 | 94 | |
|
234 | 95 | # Spawn a kernel. |
|
235 | 96 | if sys.platform == 'win32': |
|
236 | 97 | # Create a Win32 event for interrupting the kernel. |
|
237 | 98 | interrupt_event = ParentPollerWindows.create_interrupt_event() |
|
238 |
arguments += [ ' |
|
|
99 | arguments += [ 'interrupt=%i'%interrupt_event ] | |
|
239 | 100 | |
|
240 | 101 | # If this process in running on pythonw, stdin, stdout, and stderr are |
|
241 | 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 | 134 | handle = DuplicateHandle(pid, pid, pid, 0, |
|
274 | 135 | True, # Inheritable by new processes. |
|
275 | 136 | DUPLICATE_SAME_ACCESS) |
|
276 |
proc = Popen(arguments + [' |
|
|
137 | proc = Popen(arguments + ['parent=%i'%int(handle)], | |
|
277 | 138 | stdin=_stdin, stdout=_stdout, stderr=_stderr) |
|
278 | 139 | |
|
279 | 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 | 154 | proc = Popen(arguments, preexec_fn=lambda: os.setsid(), |
|
294 | 155 | stdin=stdin, stdout=stdout, stderr=stderr) |
|
295 | 156 | else: |
|
296 |
proc = Popen(arguments + [' |
|
|
157 | proc = Popen(arguments + ['parent=1'], | |
|
297 | 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 | 28 | # Local imports. |
|
29 | 29 | from IPython.config.configurable import Configurable |
|
30 | from IPython.config.application import boolean_flag | |
|
31 | from IPython.core.newapplication import ProfileDir | |
|
30 | 32 | from IPython.utils import io |
|
31 | 33 | from IPython.utils.jsonutil import json_clean |
|
32 | 34 | from IPython.lib import pylabtools |
|
33 |
from IPython.utils.traitlets import |
|
|
34 | from entry_point import (base_launch_kernel, make_argument_parser, make_kernel, | |
|
35 | start_kernel) | |
|
35 | from IPython.utils.traitlets import ( | |
|
36 | List, Instance, Float, Dict, Bool, Int, Unicode, CaselessStrEnum | |
|
37 | ) | |
|
38 | from entry_point import base_launch_kernel | |
|
39 | from kernelapp import KernelApp, kernel_flags, kernel_aliases | |
|
36 | 40 | from iostream import OutStream |
|
37 | 41 | from session import Session, Message |
|
38 | 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 | 47 | # Main kernel class |
@@ -71,9 +55,10 b' class Kernel(Configurable):' | |||
|
71 | 55 | |
|
72 | 56 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
73 | 57 | session = Instance(Session) |
|
74 |
|
|
|
75 | pub_socket = Instance('zmq.Socket') | |
|
76 |
|
|
|
58 | shell_socket = Instance('zmq.Socket') | |
|
59 | iopub_socket = Instance('zmq.Socket') | |
|
60 | stdin_socket = Instance('zmq.Socket') | |
|
61 | log = Instance(logging.Logger) | |
|
77 | 62 | |
|
78 | 63 | # Private interface |
|
79 | 64 | |
@@ -100,7 +85,8 b' class Kernel(Configurable):' | |||
|
100 | 85 | |
|
101 | 86 | # This is a dict of port number that the kernel is listening on. It is set |
|
102 | 87 | # by record_ports and used by connect_request. |
|
103 |
_recorded_ports = |
|
|
88 | _recorded_ports = Dict() | |
|
89 | ||
|
104 | 90 | |
|
105 | 91 | |
|
106 | 92 | def __init__(self, **kwargs): |
@@ -111,11 +97,11 b' class Kernel(Configurable):' | |||
|
111 | 97 | atexit.register(self._at_shutdown) |
|
112 | 98 | |
|
113 | 99 | # Initialize the InteractiveShell subclass |
|
114 | self.shell = ZMQInteractiveShell.instance() | |
|
100 | self.shell = ZMQInteractiveShell.instance(config=self.config) | |
|
115 | 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 | 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 | 106 | # TMP - hack while developing |
|
121 | 107 | self.shell._reply_content = None |
@@ -131,7 +117,7 b' class Kernel(Configurable):' | |||
|
131 | 117 | def do_one_iteration(self): |
|
132 | 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 | 121 | if msg is None: |
|
136 | 122 | return |
|
137 | 123 | |
@@ -143,21 +129,20 b' class Kernel(Configurable):' | |||
|
143 | 129 | # Print some info about this message and leave a '--->' marker, so it's |
|
144 | 130 | # easier to trace visually the message chain when debugging. Each |
|
145 | 131 | # handler prints its message at the end. |
|
146 | # Eventually we'll move these from stdout to a logger. | |
|
147 | logger.debug('\n*** MESSAGE TYPE:'+str(msg['msg_type'])+'***') | |
|
148 | logger.debug(' Content: '+str(msg['content'])+'\n --->\n ') | |
|
132 | self.log.debug('\n*** MESSAGE TYPE:'+str(msg['msg_type'])+'***') | |
|
133 | self.log.debug(' Content: '+str(msg['content'])+'\n --->\n ') | |
|
149 | 134 | |
|
150 | 135 | # Find and call actual handler for message |
|
151 | 136 | handler = self.handlers.get(msg['msg_type'], None) |
|
152 | 137 | if handler is None: |
|
153 |
log |
|
|
138 | self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg)) | |
|
154 | 139 | else: |
|
155 | 140 | handler(ident, msg) |
|
156 | 141 | |
|
157 | 142 | # Check whether we should exit, in case the incoming message set the |
|
158 | 143 | # exit flag on |
|
159 | 144 | if self.shell.exit_now: |
|
160 |
log |
|
|
145 | self.log.debug('\nExiting IPython kernel...') | |
|
161 | 146 | # We do a normal, clean exit, which allows any actions registered |
|
162 | 147 | # via atexit (such as history saving) to take place. |
|
163 | 148 | sys.exit(0) |
@@ -166,26 +151,27 b' class Kernel(Configurable):' | |||
|
166 | 151 | def start(self): |
|
167 | 152 | """ Start the kernel main loop. |
|
168 | 153 | """ |
|
154 | poller = zmq.Poller() | |
|
155 | poller.register(self.shell_socket, zmq.POLLIN) | |
|
169 | 156 | while True: |
|
170 | 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 | 163 | self.do_one_iteration() |
|
173 | 164 | except KeyboardInterrupt: |
|
174 | 165 | # Ctrl-C shouldn't crash the kernel |
|
175 | 166 | io.raw_print("KeyboardInterrupt caught in kernel") |
|
176 | 167 | |
|
177 |
def record_ports(self, |
|
|
168 | def record_ports(self, ports): | |
|
178 | 169 | """Record the ports that this kernel is using. |
|
179 | 170 | |
|
180 | 171 | The creator of the Kernel instance must call this methods if they |
|
181 | 172 | want the :meth:`connect_request` method to return the port numbers. |
|
182 | 173 | """ |
|
183 |
self._recorded_ports = |
|
|
184 | 'xrep_port' : xrep_port, | |
|
185 | 'pub_port' : pub_port, | |
|
186 | 'req_port' : req_port, | |
|
187 | 'hb_port' : hb_port | |
|
188 | } | |
|
174 | self._recorded_ports = ports | |
|
189 | 175 | |
|
190 | 176 | #--------------------------------------------------------------------------- |
|
191 | 177 | # Kernel request handlers |
@@ -194,11 +180,11 b' class Kernel(Configurable):' | |||
|
194 | 180 | def _publish_pyin(self, code, parent): |
|
195 | 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 | 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 | 188 | u'status', |
|
203 | 189 | {u'execution_state':u'busy'}, |
|
204 | 190 | parent=parent |
@@ -209,8 +195,8 b' class Kernel(Configurable):' | |||
|
209 | 195 | code = content[u'code'] |
|
210 | 196 | silent = content[u'silent'] |
|
211 | 197 | except: |
|
212 |
log |
|
|
213 |
log |
|
|
198 | self.log.error("Got bad msg: ") | |
|
199 | self.log.error(str(Message(parent))) | |
|
214 | 200 | return |
|
215 | 201 | |
|
216 | 202 | shell = self.shell # we'll need this a lot here |
@@ -298,14 +284,14 b' class Kernel(Configurable):' | |||
|
298 | 284 | time.sleep(self._execute_sleep) |
|
299 | 285 | |
|
300 | 286 | # Send the reply. |
|
301 |
reply_msg = self.session.send(self. |
|
|
287 | reply_msg = self.session.send(self.shell_socket, u'execute_reply', | |
|
302 | 288 | reply_content, parent, ident=ident) |
|
303 |
log |
|
|
289 | self.log.debug(str(reply_msg)) | |
|
304 | 290 | |
|
305 | 291 | if reply_msg['content']['status'] == u'error': |
|
306 | 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 | 295 | u'status', |
|
310 | 296 | {u'execution_state':u'idle'}, |
|
311 | 297 | parent=parent |
@@ -316,17 +302,17 b' class Kernel(Configurable):' | |||
|
316 | 302 | matches = {'matches' : matches, |
|
317 | 303 | 'matched_text' : txt, |
|
318 | 304 | 'status' : 'ok'} |
|
319 |
completion_msg = self.session.send(self. |
|
|
305 | completion_msg = self.session.send(self.shell_socket, 'complete_reply', | |
|
320 | 306 | matches, parent, ident) |
|
321 |
log |
|
|
307 | self.log.debug(str(completion_msg)) | |
|
322 | 308 | |
|
323 | 309 | def object_info_request(self, ident, parent): |
|
324 | 310 | object_info = self.shell.object_inspect(parent['content']['oname']) |
|
325 | 311 | # Before we send this object over, we scrub it for JSON usage |
|
326 | 312 | oinfo = json_clean(object_info) |
|
327 |
msg = self.session.send(self. |
|
|
313 | msg = self.session.send(self.shell_socket, 'object_info_reply', | |
|
328 | 314 | oinfo, parent, ident) |
|
329 |
log |
|
|
315 | self.log.debug(msg) | |
|
330 | 316 | |
|
331 | 317 | def history_request(self, ident, parent): |
|
332 | 318 | # We need to pull these out, as passing **kwargs doesn't work with |
@@ -353,18 +339,18 b' class Kernel(Configurable):' | |||
|
353 | 339 | else: |
|
354 | 340 | hist = [] |
|
355 | 341 | content = {'history' : list(hist)} |
|
356 |
msg = self.session.send(self. |
|
|
342 | msg = self.session.send(self.shell_socket, 'history_reply', | |
|
357 | 343 | content, parent, ident) |
|
358 |
log |
|
|
344 | self.log.debug(str(msg)) | |
|
359 | 345 | |
|
360 | 346 | def connect_request(self, ident, parent): |
|
361 | 347 | if self._recorded_ports is not None: |
|
362 | 348 | content = self._recorded_ports.copy() |
|
363 | 349 | else: |
|
364 | 350 | content = {} |
|
365 |
msg = self.session.send(self. |
|
|
351 | msg = self.session.send(self.shell_socket, 'connect_reply', | |
|
366 | 352 | content, parent, ident) |
|
367 |
log |
|
|
353 | self.log.debug(msg) | |
|
368 | 354 | |
|
369 | 355 | def shutdown_request(self, ident, parent): |
|
370 | 356 | self.shell.exit_now = True |
@@ -377,19 +363,19 b' class Kernel(Configurable):' | |||
|
377 | 363 | |
|
378 | 364 | def _abort_queue(self): |
|
379 | 365 | while True: |
|
380 |
ident,msg = self.session.recv(self. |
|
|
366 | ident,msg = self.session.recv(self.shell_socket, zmq.NOBLOCK) | |
|
381 | 367 | if msg is None: |
|
382 | 368 | break |
|
383 | 369 | else: |
|
384 | 370 | assert ident is not None, \ |
|
385 | 371 | "Unexpected missing message part." |
|
386 | 372 | |
|
387 |
log |
|
|
373 | self.log.debug("Aborting:\n"+str(Message(msg))) | |
|
388 | 374 | msg_type = msg['msg_type'] |
|
389 | 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 | 377 | {'status' : 'aborted'}, msg, ident=ident) |
|
392 |
log |
|
|
378 | self.log.debug(reply_msg) | |
|
393 | 379 | # We need to wait a bit for requests to come in. This can probably |
|
394 | 380 | # be set shorter for true asynchronous clients. |
|
395 | 381 | time.sleep(0.1) |
@@ -401,15 +387,15 b' class Kernel(Configurable):' | |||
|
401 | 387 | |
|
402 | 388 | # Send the input request. |
|
403 | 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 | 392 | # Await a response. |
|
407 |
ident, reply = self.session.recv(self. |
|
|
393 | ident, reply = self.session.recv(self.stdin_socket, 0) | |
|
408 | 394 | try: |
|
409 | 395 | value = reply['content']['value'] |
|
410 | 396 | except: |
|
411 |
log |
|
|
412 |
log |
|
|
397 | self.log.error("Got bad raw_input reply: ") | |
|
398 | self.log.error(str(Message(parent))) | |
|
413 | 399 | value = '' |
|
414 | 400 | return value |
|
415 | 401 | |
@@ -461,9 +447,9 b' class Kernel(Configurable):' | |||
|
461 | 447 | """ |
|
462 | 448 | # io.rprint("Kernel at_shutdown") # dbg |
|
463 | 449 | if self._shutdown_message is not None: |
|
464 |
self.session.send(self. |
|
|
465 | self.session.send(self.pub_socket, self._shutdown_message) | |
|
466 |
log |
|
|
450 | self.session.send(self.shell_socket, self._shutdown_message) | |
|
451 | self.session.send(self.iopub_socket, self._shutdown_message) | |
|
452 | self.log.debug(str(self._shutdown_message)) | |
|
467 | 453 | # A very short sleep to give zmq time to flush its message buffers |
|
468 | 454 | # before Python truly shuts down. |
|
469 | 455 | time.sleep(0.01) |
@@ -569,93 +555,134 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, | |
|
576 | stdin=None, stdout=None, stderr=None, | |
|
577 | executable=None, independent=False, pylab=False, colors=None): | |
|
578 | """Launches a localhost kernel, binding to the specified ports. | |
|
579 | ||
|
580 | Parameters | |
|
581 | ---------- | |
|
582 | ip : str, optional | |
|
583 | The ip address the kernel will bind to. | |
|
584 | ||
|
585 | xrep_port : int, optional | |
|
586 | The port to use for XREP channel. | |
|
587 | ||
|
588 | pub_port : int, optional | |
|
589 | The port to use for the SUB channel. | |
|
561 | flags = dict(kernel_flags) | |
|
590 | 562 | |
|
591 | req_port : int, optional | |
|
592 | The port to use for the REQ (raw input) channel. | |
|
593 | ||
|
594 | hb_port : int, optional | |
|
595 | The port to use for the hearbeat REP channel. | |
|
563 | addflag = lambda *args: flags.update(boolean_flag(*args)) | |
|
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 | ) | |
|
596 | 609 | |
|
597 | stdin, stdout, stderr : optional (default None) | |
|
598 | Standards streams, as defined in subprocess.Popen. | |
|
610 | flags['pylab'] = ( | |
|
611 | {'IPKernelApp' : {'pylab' : 'auto'}}, | |
|
612 | """Pre-load matplotlib and numpy for interactive use with | |
|
613 | the default matplotlib backend.""" | |
|
614 | ) | |
|
599 | 615 | |
|
600 | executable : str, optional (default sys.executable) | |
|
601 | The Python executable to use for the kernel process. | |
|
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 | )) | |
|
602 | 636 | |
|
603 | independent : bool, optional (default False) | |
|
604 | If set, the kernel process is guaranteed to survive if this process | |
|
605 | dies. If not set, an effort is made to ensure that the kernel is killed | |
|
606 | when this process dies. Note that in this case it is still good practice | |
|
607 | to kill kernels manually before exiting. | |
|
637 | #----------------------------------------------------------------------------- | |
|
638 | # The IPKernelApp class | |
|
639 | #----------------------------------------------------------------------------- | |
|
608 | 640 | |
|
609 | pylab : bool or string, optional (default False) | |
|
610 | If not False, the kernel will be launched with pylab enabled. If a | |
|
611 | string is passed, matplotlib will use the specified backend. Otherwise, | |
|
612 | matplotlib's default backend will be used. | |
|
641 | class IPKernelApp(KernelApp): | |
|
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) | |
|
613 | 664 | |
|
614 | colors : None or string, optional (default None) | |
|
615 | If not None, specify the color scheme. One of (NoColor, LightBG, Linux) | |
|
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) | |
|
616 | 672 | |
|
617 | Returns | |
|
618 | ------- | |
|
619 | A tuple of form: | |
|
620 | (kernel_process, xrep_port, pub_port, req_port) | |
|
621 | where kernel_process is a Popen object and the ports are integers. | |
|
622 |
|
|
|
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()', | |
|
636 | xrep_port, pub_port, req_port, hb_port, | |
|
637 | stdin, stdout, stderr, | |
|
638 | executable, independent, extra_arguments) | |
|
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) | |
|
639 | 681 | |
|
682 | def init_kernel(self): | |
|
683 | kernel_factory = Kernel | |
|
640 | 684 | |
|
641 | def main(): | |
|
642 | """ The IPython kernel main entry point. | |
|
643 | """ | |
|
644 | parser = make_argument_parser() | |
|
645 | parser.add_argument('--pylab', type=str, metavar='GUI', nargs='?', | |
|
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 = { | |
|
685 | kernel_map = { | |
|
659 | 686 | 'qt' : QtKernel, |
|
660 | 687 | 'qt4': QtKernel, |
|
661 | 688 | 'inline': Kernel, |
@@ -664,25 +691,55 b" given, the GUI backend is matplotlib's, otherwise use one of: \\" | |||
|
664 | 691 | 'tk' : TkKernel, |
|
665 | 692 | 'gtk': GTKKernel, |
|
666 | 693 | } |
|
667 | if namespace.pylab: | |
|
668 |
if |
|
|
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: | |
|
694 | ||
|
695 | if self.pylab: | |
|
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: | |
|
674 | 700 | raise ValueError('GUI is not supported: %r' % gui) |
|
675 | 701 | pylabtools.activate_matplotlib(backend) |
|
676 | if namespace.colors: | |
|
677 | ZMQInteractiveShell.colors=namespace.colors | |
|
678 | 702 | |
|
679 | kernel = make_kernel(namespace, kernel_class, OutStream) | |
|
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) | |
|
680 | 711 | |
|
681 |
if |
|
|
712 | if self.pylab: | |
|
682 | 713 | pylabtools.import_pylab(kernel.shell.user_ns, backend, |
|
683 | 714 | shell=kernel.shell) |
|
684 | 715 | |
|
685 | start_kernel(namespace, kernel) | |
|
716 | ||
|
717 | ||
|
718 | #----------------------------------------------------------------------------- | |
|
719 | # Kernel main and launch functions | |
|
720 | #----------------------------------------------------------------------------- | |
|
721 | ||
|
722 | def launch_kernel(*args, **kwargs): | |
|
723 | """Launches a localhost IPython kernel, binding to the specified ports. | |
|
724 | ||
|
725 | This function simply calls entry_point.base_launch_kernel with the right first | |
|
726 | command to start an ipkernel. See base_launch_kernel for arguments. | |
|
727 | ||
|
728 | Returns | |
|
729 | ------- | |
|
730 | A tuple of form: | |
|
731 | (kernel_process, shell_port, iopub_port, stdin_port, hb_port) | |
|
732 | where kernel_process is a Popen object and the ports are integers. | |
|
733 | """ | |
|
734 | return base_launch_kernel('from IPython.zmq.ipkernel import main; main()', | |
|
735 | *args, **kwargs) | |
|
736 | ||
|
737 | ||
|
738 | def main(): | |
|
739 | """Run a PyKernel as an application""" | |
|
740 | app = IPKernelApp() | |
|
741 | app.initialize() | |
|
742 | app.start() | |
|
686 | 743 | |
|
687 | 744 | |
|
688 | 745 | if __name__ == '__main__': |
@@ -782,8 +782,8 b' class KernelManager(HasTraits):' | |||
|
782 | 782 | else: |
|
783 | 783 | from pykernel import launch_kernel |
|
784 | 784 | self.kernel, xrep, pub, req, _hb = launch_kernel( |
|
785 |
|
|
|
786 |
|
|
|
785 | shell_port=xreq[1], iopub_port=sub[1], | |
|
786 | stdin_port=rep[1], hb_port=hb[1], **kw) | |
|
787 | 787 | self.xreq_address = (xreq[0], xrep) |
|
788 | 788 | self.sub_address = (sub[0], pub) |
|
789 | 789 | self.rep_address = (rep[0], req) |
@@ -25,10 +25,11 b' import traceback' | |||
|
25 | 25 | import zmq |
|
26 | 26 | |
|
27 | 27 | # Local imports. |
|
28 | from IPython.utils.traitlets import HasTraits, Instance, Float | |
|
28 | from IPython.utils.traitlets import HasTraits, Instance, Dict, Float | |
|
29 | 29 | from completer import KernelCompleter |
|
30 |
from entry_point import base_launch_kernel |
|
|
30 | from entry_point import base_launch_kernel | |
|
31 | 31 | from session import Session, Message |
|
32 | from kernelapp import KernelApp | |
|
32 | 33 | |
|
33 | 34 | #----------------------------------------------------------------------------- |
|
34 | 35 | # Main kernel class |
@@ -49,16 +50,16 b' class Kernel(HasTraits):' | |||
|
49 | 50 | |
|
50 | 51 | # This is a dict of port number that the kernel is listening on. It is set |
|
51 | 52 | # by record_ports and used by connect_request. |
|
52 |
_recorded_ports = |
|
|
53 | _recorded_ports = Dict() | |
|
53 | 54 | |
|
54 | 55 | #--------------------------------------------------------------------------- |
|
55 | 56 | # Kernel interface |
|
56 | 57 | #--------------------------------------------------------------------------- |
|
57 | 58 | |
|
58 | 59 | session = Instance(Session) |
|
59 |
|
|
|
60 | pub_socket = Instance('zmq.Socket') | |
|
61 |
|
|
|
60 | shell_socket = Instance('zmq.Socket') | |
|
61 | iopub_socket = Instance('zmq.Socket') | |
|
62 | stdin_socket = Instance('zmq.Socket') | |
|
62 | 63 | |
|
63 | 64 | def __init__(self, **kwargs): |
|
64 | 65 | super(Kernel, self).__init__(**kwargs) |
@@ -78,7 +79,7 b' class Kernel(HasTraits):' | |||
|
78 | 79 | """ Start the kernel main loop. |
|
79 | 80 | """ |
|
80 | 81 | while True: |
|
81 |
ident,msg = self.session.recv(self. |
|
|
82 | ident,msg = self.session.recv(self.shell_socket,0) | |
|
82 | 83 | assert ident is not None, "Missing message part." |
|
83 | 84 | omsg = Message(msg) |
|
84 | 85 | print>>sys.__stdout__ |
@@ -89,18 +90,13 b' class Kernel(HasTraits):' | |||
|
89 | 90 | else: |
|
90 | 91 | handler(ident, omsg) |
|
91 | 92 | |
|
92 |
def record_ports(self, |
|
|
93 | def record_ports(self, ports): | |
|
93 | 94 | """Record the ports that this kernel is using. |
|
94 | 95 | |
|
95 | 96 | The creator of the Kernel instance must call this methods if they |
|
96 | 97 | want the :meth:`connect_request` method to return the port numbers. |
|
97 | 98 | """ |
|
98 |
self._recorded_ports = |
|
|
99 | 'xrep_port' : xrep_port, | |
|
100 | 'pub_port' : pub_port, | |
|
101 | 'req_port' : req_port, | |
|
102 | 'hb_port' : hb_port | |
|
103 | } | |
|
99 | self._recorded_ports = ports | |
|
104 | 100 | |
|
105 | 101 | #--------------------------------------------------------------------------- |
|
106 | 102 | # Kernel request handlers |
@@ -113,7 +109,7 b' class Kernel(HasTraits):' | |||
|
113 | 109 | print>>sys.__stderr__, "Got bad msg: " |
|
114 | 110 | print>>sys.__stderr__, Message(parent) |
|
115 | 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 | 114 | try: |
|
119 | 115 | comp_code = self.compiler(code, '<zmq-kernel>') |
@@ -138,7 +134,7 b' class Kernel(HasTraits):' | |||
|
138 | 134 | u'ename' : unicode(etype.__name__), |
|
139 | 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 | 138 | reply_content = exc_content |
|
143 | 139 | else: |
|
144 | 140 | reply_content = { 'status' : 'ok', 'payload' : {} } |
@@ -153,7 +149,7 b' class Kernel(HasTraits):' | |||
|
153 | 149 | time.sleep(self._execute_sleep) |
|
154 | 150 | |
|
155 | 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 | 153 | print>>sys.__stdout__, Message(reply_msg) |
|
158 | 154 | if reply_msg['content']['status'] == u'error': |
|
159 | 155 | self._abort_queue() |
@@ -161,22 +157,22 b' class Kernel(HasTraits):' | |||
|
161 | 157 | def complete_request(self, ident, parent): |
|
162 | 158 | matches = {'matches' : self._complete(parent), |
|
163 | 159 | 'status' : 'ok'} |
|
164 |
completion_msg = self.session.send(self. |
|
|
160 | completion_msg = self.session.send(self.shell_socket, 'complete_reply', | |
|
165 | 161 | matches, parent, ident) |
|
166 | 162 | print >> sys.__stdout__, completion_msg |
|
167 | 163 | |
|
168 | 164 | def object_info_request(self, ident, parent): |
|
169 | 165 | context = parent['content']['oname'].split('.') |
|
170 | 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 | 168 | object_info, parent, ident) |
|
173 | 169 | print >> sys.__stdout__, msg |
|
174 | 170 | |
|
175 | 171 | def shutdown_request(self, ident, parent): |
|
176 | 172 | content = dict(parent['content']) |
|
177 |
msg = self.session.send(self. |
|
|
173 | msg = self.session.send(self.shell_socket, 'shutdown_reply', | |
|
178 | 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 | 176 | content, parent, ident) |
|
181 | 177 | print >> sys.__stdout__, msg |
|
182 | 178 | time.sleep(0.1) |
@@ -197,7 +193,7 b' class Kernel(HasTraits):' | |||
|
197 | 193 | print>>sys.__stdout__, Message(msg) |
|
198 | 194 | msg_type = msg['msg_type'] |
|
199 | 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 | 197 | print>>sys.__stdout__, Message(reply_msg) |
|
202 | 198 | # We need to wait a bit for requests to come in. This can probably |
|
203 | 199 | # be set shorter for true asynchronous clients. |
@@ -210,10 +206,10 b' class Kernel(HasTraits):' | |||
|
210 | 206 | |
|
211 | 207 | # Send the input request. |
|
212 | 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 | 211 | # Await a response. |
|
216 |
ident,reply = self.session.recv(self. |
|
|
212 | ident,reply = self.session.recv(self.stdin_socket, 0) | |
|
217 | 213 | try: |
|
218 | 214 | value = reply['content']['value'] |
|
219 | 215 | except: |
@@ -259,58 +255,26 b' class Kernel(HasTraits):' | |||
|
259 | 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, | |
|
263 | stdin=None, stdout=None, stderr=None, | |
|
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 | ||
|
272 | xrep_port : int, optional | |
|
273 | The port to use for XREP channel. | |
|
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. | |
|
258 | def launch_kernel(*args, **kwargs): | |
|
259 | """ Launches a simple Python kernel, binding to the specified ports. | |
|
280 | 260 | |
|
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. | |
|
261 | This function simply calls entry_point.base_launch_kernel with the right first | |
|
262 | command to start a pykernel. See base_launch_kernel for arguments. | |
|
295 | 263 | |
|
296 | 264 | Returns |
|
297 | 265 | ------- |
|
298 | 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 | 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 | 270 | return base_launch_kernel('from IPython.zmq.pykernel import main; main()', |
|
309 | xrep_port, pub_port, req_port, hb_port, | |
|
310 | stdin, stdout, stderr, | |
|
311 | executable, independent, extra_arguments) | |
|
271 | *args, **kwargs) | |
|
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 | 279 | if __name__ == '__main__': |
|
316 | 280 | main() |
General Comments 0
You need to be logged in to leave comments.
Login now