##// END OF EJS Templates
Small fix for API consistency.
epatters -
Show More
@@ -1,409 +1,410 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 """A simple interactive kernel that talks to a frontend over 0MQ.
2 """A simple interactive kernel that talks to a frontend over 0MQ.
3
3
4 Things to do:
4 Things to do:
5
5
6 * Finish implementing `raw_input`.
6 * Finish implementing `raw_input`.
7 * Implement `set_parent` logic. Right before doing exec, the Kernel should
7 * Implement `set_parent` logic. Right before doing exec, the Kernel should
8 call set_parent on all the PUB objects with the message about to be executed.
8 call set_parent on all the PUB objects with the message about to be executed.
9 * Implement random port and security key logic.
9 * Implement random port and security key logic.
10 * Implement control messages.
10 * Implement control messages.
11 * Implement event loop and poll version.
11 * Implement event loop and poll version.
12 """
12 """
13
13
14 # Standard library imports.
14 # Standard library imports.
15 import __builtin__
15 import __builtin__
16 import os
16 import os
17 import sys
17 import sys
18 import time
18 import time
19 import traceback
19 import traceback
20 from code import CommandCompiler
20 from code import CommandCompiler
21
21
22 # System library imports.
22 # System library imports.
23 import zmq
23 import zmq
24
24
25 # Local imports.
25 # Local imports.
26 from IPython.external.argparse import ArgumentParser
26 from IPython.external.argparse import ArgumentParser
27 from session import Session, Message, extract_header
27 from session import Session, Message, extract_header
28 from completer import KernelCompleter
28 from completer import KernelCompleter
29
29
30
30
31 class OutStream(object):
31 class OutStream(object):
32 """A file like object that publishes the stream to a 0MQ PUB socket."""
32 """A file like object that publishes the stream to a 0MQ PUB socket."""
33
33
34 def __init__(self, session, pub_socket, name, max_buffer=200):
34 def __init__(self, session, pub_socket, name, max_buffer=200):
35 self.session = session
35 self.session = session
36 self.pub_socket = pub_socket
36 self.pub_socket = pub_socket
37 self.name = name
37 self.name = name
38 self._buffer = []
38 self._buffer = []
39 self._buffer_len = 0
39 self._buffer_len = 0
40 self.max_buffer = max_buffer
40 self.max_buffer = max_buffer
41 self.parent_header = {}
41 self.parent_header = {}
42
42
43 def set_parent(self, parent):
43 def set_parent(self, parent):
44 self.parent_header = extract_header(parent)
44 self.parent_header = extract_header(parent)
45
45
46 def close(self):
46 def close(self):
47 self.pub_socket = None
47 self.pub_socket = None
48
48
49 def flush(self):
49 def flush(self):
50 if self.pub_socket is None:
50 if self.pub_socket is None:
51 raise ValueError(u'I/O operation on closed file')
51 raise ValueError(u'I/O operation on closed file')
52 else:
52 else:
53 if self._buffer:
53 if self._buffer:
54 data = ''.join(self._buffer)
54 data = ''.join(self._buffer)
55 content = {u'name':self.name, u'data':data}
55 content = {u'name':self.name, u'data':data}
56 msg = self.session.msg(u'stream', content=content,
56 msg = self.session.msg(u'stream', content=content,
57 parent=self.parent_header)
57 parent=self.parent_header)
58 print>>sys.__stdout__, Message(msg)
58 print>>sys.__stdout__, Message(msg)
59 self.pub_socket.send_json(msg)
59 self.pub_socket.send_json(msg)
60 self._buffer_len = 0
60 self._buffer_len = 0
61 self._buffer = []
61 self._buffer = []
62
62
63 def isattr(self):
63 def isattr(self):
64 return False
64 return False
65
65
66 def next(self):
66 def next(self):
67 raise IOError('Read not supported on a write only stream.')
67 raise IOError('Read not supported on a write only stream.')
68
68
69 def read(self, size=None):
69 def read(self, size=None):
70 raise IOError('Read not supported on a write only stream.')
70 raise IOError('Read not supported on a write only stream.')
71
71
72 readline=read
72 readline=read
73
73
74 def write(self, s):
74 def write(self, s):
75 if self.pub_socket is None:
75 if self.pub_socket is None:
76 raise ValueError('I/O operation on closed file')
76 raise ValueError('I/O operation on closed file')
77 else:
77 else:
78 self._buffer.append(s)
78 self._buffer.append(s)
79 self._buffer_len += len(s)
79 self._buffer_len += len(s)
80 self._maybe_send()
80 self._maybe_send()
81
81
82 def _maybe_send(self):
82 def _maybe_send(self):
83 if '\n' in self._buffer[-1]:
83 if '\n' in self._buffer[-1]:
84 self.flush()
84 self.flush()
85 if self._buffer_len > self.max_buffer:
85 if self._buffer_len > self.max_buffer:
86 self.flush()
86 self.flush()
87
87
88 def writelines(self, sequence):
88 def writelines(self, sequence):
89 if self.pub_socket is None:
89 if self.pub_socket is None:
90 raise ValueError('I/O operation on closed file')
90 raise ValueError('I/O operation on closed file')
91 else:
91 else:
92 for s in sequence:
92 for s in sequence:
93 self.write(s)
93 self.write(s)
94
94
95
95
96 class DisplayHook(object):
96 class DisplayHook(object):
97
97
98 def __init__(self, session, pub_socket):
98 def __init__(self, session, pub_socket):
99 self.session = session
99 self.session = session
100 self.pub_socket = pub_socket
100 self.pub_socket = pub_socket
101 self.parent_header = {}
101 self.parent_header = {}
102
102
103 def __call__(self, obj):
103 def __call__(self, obj):
104 if obj is None:
104 if obj is None:
105 return
105 return
106
106
107 __builtin__._ = obj
107 __builtin__._ = obj
108 msg = self.session.msg(u'pyout', {u'data':repr(obj)},
108 msg = self.session.msg(u'pyout', {u'data':repr(obj)},
109 parent=self.parent_header)
109 parent=self.parent_header)
110 self.pub_socket.send_json(msg)
110 self.pub_socket.send_json(msg)
111
111
112 def set_parent(self, parent):
112 def set_parent(self, parent):
113 self.parent_header = extract_header(parent)
113 self.parent_header = extract_header(parent)
114
114
115
115
116 class RawInput(object):
116 class RawInput(object):
117
117
118 def __init__(self, session, socket):
118 def __init__(self, session, socket):
119 self.session = session
119 self.session = session
120 self.socket = socket
120 self.socket = socket
121
121
122 def __call__(self, prompt=None):
122 def __call__(self, prompt=None):
123 msg = self.session.msg(u'raw_input')
123 msg = self.session.msg(u'raw_input')
124 self.socket.send_json(msg)
124 self.socket.send_json(msg)
125 while True:
125 while True:
126 try:
126 try:
127 reply = self.socket.recv_json(zmq.NOBLOCK)
127 reply = self.socket.recv_json(zmq.NOBLOCK)
128 except zmq.ZMQError, e:
128 except zmq.ZMQError, e:
129 if e.errno == zmq.EAGAIN:
129 if e.errno == zmq.EAGAIN:
130 pass
130 pass
131 else:
131 else:
132 raise
132 raise
133 else:
133 else:
134 break
134 break
135 return reply[u'content'][u'data']
135 return reply[u'content'][u'data']
136
136
137
137
138 class Kernel(object):
138 class Kernel(object):
139
139
140 def __init__(self, session, reply_socket, pub_socket):
140 def __init__(self, session, reply_socket, pub_socket):
141 self.session = session
141 self.session = session
142 self.reply_socket = reply_socket
142 self.reply_socket = reply_socket
143 self.pub_socket = pub_socket
143 self.pub_socket = pub_socket
144 self.user_ns = {}
144 self.user_ns = {}
145 self.history = []
145 self.history = []
146 self.compiler = CommandCompiler()
146 self.compiler = CommandCompiler()
147 self.completer = KernelCompleter(self.user_ns)
147 self.completer = KernelCompleter(self.user_ns)
148 self.poll_ppid = False
148 self.poll_ppid = False
149
149
150 # Build dict of handlers for message types
150 # Build dict of handlers for message types
151 msg_types = [ 'execute_request', 'complete_request',
151 msg_types = [ 'execute_request', 'complete_request',
152 'object_info_request' ]
152 'object_info_request' ]
153 self.handlers = {}
153 self.handlers = {}
154 for msg_type in msg_types:
154 for msg_type in msg_types:
155 self.handlers[msg_type] = getattr(self, msg_type)
155 self.handlers[msg_type] = getattr(self, msg_type)
156
156
157 def abort_queue(self):
157 def abort_queue(self):
158 while True:
158 while True:
159 try:
159 try:
160 ident = self.reply_socket.recv(zmq.NOBLOCK)
160 ident = self.reply_socket.recv(zmq.NOBLOCK)
161 except zmq.ZMQError, e:
161 except zmq.ZMQError, e:
162 if e.errno == zmq.EAGAIN:
162 if e.errno == zmq.EAGAIN:
163 break
163 break
164 else:
164 else:
165 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
165 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
166 msg = self.reply_socket.recv_json()
166 msg = self.reply_socket.recv_json()
167 print>>sys.__stdout__, "Aborting:"
167 print>>sys.__stdout__, "Aborting:"
168 print>>sys.__stdout__, Message(msg)
168 print>>sys.__stdout__, Message(msg)
169 msg_type = msg['msg_type']
169 msg_type = msg['msg_type']
170 reply_type = msg_type.split('_')[0] + '_reply'
170 reply_type = msg_type.split('_')[0] + '_reply'
171 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
171 reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
172 print>>sys.__stdout__, Message(reply_msg)
172 print>>sys.__stdout__, Message(reply_msg)
173 self.reply_socket.send(ident,zmq.SNDMORE)
173 self.reply_socket.send(ident,zmq.SNDMORE)
174 self.reply_socket.send_json(reply_msg)
174 self.reply_socket.send_json(reply_msg)
175 # We need to wait a bit for requests to come in. This can probably
175 # We need to wait a bit for requests to come in. This can probably
176 # be set shorter for true asynchronous clients.
176 # be set shorter for true asynchronous clients.
177 time.sleep(0.1)
177 time.sleep(0.1)
178
178
179 def execute_request(self, ident, parent):
179 def execute_request(self, ident, parent):
180 try:
180 try:
181 code = parent[u'content'][u'code']
181 code = parent[u'content'][u'code']
182 except:
182 except:
183 print>>sys.__stderr__, "Got bad msg: "
183 print>>sys.__stderr__, "Got bad msg: "
184 print>>sys.__stderr__, Message(parent)
184 print>>sys.__stderr__, Message(parent)
185 return
185 return
186 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
186 pyin_msg = self.session.msg(u'pyin',{u'code':code}, parent=parent)
187 self.pub_socket.send_json(pyin_msg)
187 self.pub_socket.send_json(pyin_msg)
188 try:
188 try:
189 comp_code = self.compiler(code, '<zmq-kernel>')
189 comp_code = self.compiler(code, '<zmq-kernel>')
190 sys.displayhook.set_parent(parent)
190 sys.displayhook.set_parent(parent)
191 exec comp_code in self.user_ns, self.user_ns
191 exec comp_code in self.user_ns, self.user_ns
192 except:
192 except:
193 result = u'error'
193 result = u'error'
194 etype, evalue, tb = sys.exc_info()
194 etype, evalue, tb = sys.exc_info()
195 tb = traceback.format_exception(etype, evalue, tb)
195 tb = traceback.format_exception(etype, evalue, tb)
196 exc_content = {
196 exc_content = {
197 u'status' : u'error',
197 u'status' : u'error',
198 u'traceback' : tb,
198 u'traceback' : tb,
199 u'etype' : unicode(etype),
199 u'etype' : unicode(etype),
200 u'evalue' : unicode(evalue)
200 u'evalue' : unicode(evalue)
201 }
201 }
202 exc_msg = self.session.msg(u'pyerr', exc_content, parent)
202 exc_msg = self.session.msg(u'pyerr', exc_content, parent)
203 self.pub_socket.send_json(exc_msg)
203 self.pub_socket.send_json(exc_msg)
204 reply_content = exc_content
204 reply_content = exc_content
205 else:
205 else:
206 reply_content = {'status' : 'ok'}
206 reply_content = {'status' : 'ok'}
207 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
207 reply_msg = self.session.msg(u'execute_reply', reply_content, parent)
208 print>>sys.__stdout__, Message(reply_msg)
208 print>>sys.__stdout__, Message(reply_msg)
209 self.reply_socket.send(ident, zmq.SNDMORE)
209 self.reply_socket.send(ident, zmq.SNDMORE)
210 self.reply_socket.send_json(reply_msg)
210 self.reply_socket.send_json(reply_msg)
211 if reply_msg['content']['status'] == u'error':
211 if reply_msg['content']['status'] == u'error':
212 self.abort_queue()
212 self.abort_queue()
213
213
214 def complete_request(self, ident, parent):
214 def complete_request(self, ident, parent):
215 matches = {'matches' : self.complete(parent),
215 matches = {'matches' : self.complete(parent),
216 'status' : 'ok'}
216 'status' : 'ok'}
217 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
217 completion_msg = self.session.send(self.reply_socket, 'complete_reply',
218 matches, parent, ident)
218 matches, parent, ident)
219 print >> sys.__stdout__, completion_msg
219 print >> sys.__stdout__, completion_msg
220
220
221 def complete(self, msg):
221 def complete(self, msg):
222 return self.completer.complete(msg.content.line, msg.content.text)
222 return self.completer.complete(msg.content.line, msg.content.text)
223
223
224 def object_info_request(self, ident, parent):
224 def object_info_request(self, ident, parent):
225 context = parent['content']['oname'].split('.')
225 context = parent['content']['oname'].split('.')
226 object_info = self.object_info(context)
226 object_info = self.object_info(context)
227 msg = self.session.send(self.reply_socket, 'object_info_reply',
227 msg = self.session.send(self.reply_socket, 'object_info_reply',
228 object_info, parent, ident)
228 object_info, parent, ident)
229 print >> sys.__stdout__, msg
229 print >> sys.__stdout__, msg
230
230
231 def object_info(self, context):
231 def object_info(self, context):
232 symbol, leftover = self.symbol_from_context(context)
232 symbol, leftover = self.symbol_from_context(context)
233 if symbol is not None and not leftover:
233 if symbol is not None and not leftover:
234 doc = getattr(symbol, '__doc__', '')
234 doc = getattr(symbol, '__doc__', '')
235 else:
235 else:
236 doc = ''
236 doc = ''
237 object_info = dict(docstring = doc)
237 object_info = dict(docstring = doc)
238 return object_info
238 return object_info
239
239
240 def symbol_from_context(self, context):
240 def symbol_from_context(self, context):
241 if not context:
241 if not context:
242 return None, context
242 return None, context
243
243
244 base_symbol_string = context[0]
244 base_symbol_string = context[0]
245 symbol = self.user_ns.get(base_symbol_string, None)
245 symbol = self.user_ns.get(base_symbol_string, None)
246 if symbol is None:
246 if symbol is None:
247 symbol = __builtin__.__dict__.get(base_symbol_string, None)
247 symbol = __builtin__.__dict__.get(base_symbol_string, None)
248 if symbol is None:
248 if symbol is None:
249 return None, context
249 return None, context
250
250
251 context = context[1:]
251 context = context[1:]
252 for i, name in enumerate(context):
252 for i, name in enumerate(context):
253 new_symbol = getattr(symbol, name, None)
253 new_symbol = getattr(symbol, name, None)
254 if new_symbol is None:
254 if new_symbol is None:
255 return symbol, context[i:]
255 return symbol, context[i:]
256 else:
256 else:
257 symbol = new_symbol
257 symbol = new_symbol
258
258
259 return symbol, []
259 return symbol, []
260
260
261 def start(self):
261 def start(self):
262 while True:
262 while True:
263 if self.poll_ppid and os.getppid() == 1:
263 if self.poll_ppid and os.getppid() == 1:
264 print>>sys.__stderr__, "KILLED KERNEL. No parent process."
264 print>>sys.__stderr__, "KILLED KERNEL. No parent process."
265 os._exit(1)
265 os._exit(1)
266
266
267 ident = self.reply_socket.recv()
267 ident = self.reply_socket.recv()
268 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
268 assert self.reply_socket.rcvmore(), "Unexpected missing message part."
269 msg = self.reply_socket.recv_json()
269 msg = self.reply_socket.recv_json()
270 omsg = Message(msg)
270 omsg = Message(msg)
271 print>>sys.__stdout__
271 print>>sys.__stdout__
272 print>>sys.__stdout__, omsg
272 print>>sys.__stdout__, omsg
273 handler = self.handlers.get(omsg.msg_type, None)
273 handler = self.handlers.get(omsg.msg_type, None)
274 if handler is None:
274 if handler is None:
275 print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
275 print >> sys.__stderr__, "UNKNOWN MESSAGE TYPE:", omsg
276 else:
276 else:
277 handler(ident, omsg)
277 handler(ident, omsg)
278
278
279
279
280 def bind_port(socket, ip, port):
280 def bind_port(socket, ip, port):
281 """ Binds the specified ZMQ socket. If the port is less than zero, a random
281 """ Binds the specified ZMQ socket. If the port is less than zero, a random
282 port is chosen. Returns the port that was bound.
282 port is chosen. Returns the port that was bound.
283 """
283 """
284 connection = 'tcp://%s' % ip
284 connection = 'tcp://%s' % ip
285 if port < 0:
285 if port <= 0:
286 port = socket.bind_to_random_port(connection)
286 port = socket.bind_to_random_port(connection)
287 else:
287 else:
288 connection += ':%i' % port
288 connection += ':%i' % port
289 socket.bind(connection)
289 socket.bind(connection)
290 return port
290 return port
291
291
292 def main():
292 def main():
293 """ Main entry point for launching a kernel.
293 """ Main entry point for launching a kernel.
294 """
294 """
295 # Parse command line arguments.
295 # Parse command line arguments.
296 parser = ArgumentParser()
296 parser = ArgumentParser()
297 parser.add_argument('--ip', type=str, default='127.0.0.1',
297 parser.add_argument('--ip', type=str, default='127.0.0.1',
298 help='set the kernel\'s IP address [default: local]')
298 help='set the kernel\'s IP address [default: local]')
299 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
299 parser.add_argument('--xrep', type=int, metavar='PORT', default=0,
300 help='set the XREP channel port [default: random]')
300 help='set the XREP channel port [default: random]')
301 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
301 parser.add_argument('--pub', type=int, metavar='PORT', default=0,
302 help='set the PUB channel port [default: random]')
302 help='set the PUB channel port [default: random]')
303 parser.add_argument('--req', type=int, metavar='PORT', default=0,
303 parser.add_argument('--req', type=int, metavar='PORT', default=0,
304 help='set the REQ channel port [default: random]')
304 help='set the REQ channel port [default: random]')
305 parser.add_argument('--require-parent', action='store_true',
305 parser.add_argument('--require-parent', action='store_true',
306 help='ensure that this process dies with its parent')
306 help='ensure that this process dies with its parent')
307 namespace = parser.parse_args()
307 namespace = parser.parse_args()
308
308
309 # Create a context, a session, and the kernel sockets.
309 # Create a context, a session, and the kernel sockets.
310 print >>sys.__stdout__, "Starting the kernel..."
310 print >>sys.__stdout__, "Starting the kernel..."
311 context = zmq.Context()
311 context = zmq.Context()
312 session = Session(username=u'kernel')
312 session = Session(username=u'kernel')
313
313
314 reply_socket = context.socket(zmq.XREP)
314 reply_socket = context.socket(zmq.XREP)
315 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
315 xrep_port = bind_port(reply_socket, namespace.ip, namespace.xrep)
316 print >>sys.__stdout__, "XREP Channel on port", xrep_port
316 print >>sys.__stdout__, "XREP Channel on port", xrep_port
317
317
318 pub_socket = context.socket(zmq.PUB)
318 pub_socket = context.socket(zmq.PUB)
319 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
319 pub_port = bind_port(pub_socket, namespace.ip, namespace.pub)
320 print >>sys.__stdout__, "PUB Channel on port", pub_port
320 print >>sys.__stdout__, "PUB Channel on port", pub_port
321
321
322 # Redirect input streams and set a display hook.
322 # Redirect input streams and set a display hook.
323 sys.stdout = OutStream(session, pub_socket, u'stdout')
323 sys.stdout = OutStream(session, pub_socket, u'stdout')
324 sys.stderr = OutStream(session, pub_socket, u'stderr')
324 sys.stderr = OutStream(session, pub_socket, u'stderr')
325 sys.displayhook = DisplayHook(session, pub_socket)
325 sys.displayhook = DisplayHook(session, pub_socket)
326
326
327 # Create the kernel.
327 # Create the kernel.
328 kernel = Kernel(session, reply_socket, pub_socket)
328 kernel = Kernel(session, reply_socket, pub_socket)
329
329
330 # Configure this kernel/process to die on parent termination, if necessary.
330 # Configure this kernel/process to die on parent termination, if necessary.
331 if namespace.require_parent:
331 if namespace.require_parent:
332 if sys.platform == 'linux2':
332 if sys.platform == 'linux2':
333 import ctypes, ctypes.util, signal
333 import ctypes, ctypes.util, signal
334 PR_SET_PDEATHSIG = 1
334 PR_SET_PDEATHSIG = 1
335 libc = ctypes.CDLL(ctypes.util.find_library('c'))
335 libc = ctypes.CDLL(ctypes.util.find_library('c'))
336 libc.prctl(PR_SET_PDEATHSIG, signal.SIGKILL)
336 libc.prctl(PR_SET_PDEATHSIG, signal.SIGKILL)
337
337
338 elif sys.platform != 'win32':
338 elif sys.platform != 'win32':
339 kernel.poll_ppid = True
339 kernel.poll_ppid = True
340
340
341 # Start the kernel mainloop.
341 # Start the kernel mainloop.
342 kernel.start()
342 kernel.start()
343
343
344
344 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False):
345 def launch_kernel(xrep_port=0, pub_port=0, req_port=0, independent=False):
345 """ Launches a localhost kernel, binding to the specified ports.
346 """ Launches a localhost kernel, binding to the specified ports.
346
347
347 Parameters
348 Parameters
348 ----------
349 ----------
349 xrep_port : int, optional
350 xrep_port : int, optional
350 The port to use for XREP channel.
351 The port to use for XREP channel.
351
352
352 pub_port : int, optional
353 pub_port : int, optional
353 The port to use for the SUB channel.
354 The port to use for the SUB channel.
354
355
355 req_port : int, optional
356 req_port : int, optional
356 The port to use for the REQ (raw input) channel.
357 The port to use for the REQ (raw input) channel.
357
358
358 independent : bool, optional (default False)
359 independent : bool, optional (default False)
359 If set, the kernel process is guaranteed to survive if this process
360 If set, the kernel process is guaranteed to survive if this process
360 dies. If not set, an effort is made to ensure that the kernel is killed
361 dies. If not set, an effort is made to ensure that the kernel is killed
361 when this process dies. Note that in this case it is still good practice
362 when this process dies. Note that in this case it is still good practice
362 to attempt to kill kernels manually before exiting.
363 to attempt to kill kernels manually before exiting.
363
364
364 Returns
365 Returns
365 -------
366 -------
366 A tuple of form:
367 A tuple of form:
367 (kernel_process, xrep_port, pub_port, req_port)
368 (kernel_process, xrep_port, pub_port, req_port)
368 where kernel_process is a Popen object and the ports are integers.
369 where kernel_process is a Popen object and the ports are integers.
369 """
370 """
370 import socket
371 import socket
371 from subprocess import Popen
372 from subprocess import Popen
372
373
373 # Find open ports as necessary.
374 # Find open ports as necessary.
374 ports = []
375 ports = []
375 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
376 ports_needed = int(xrep_port <= 0) + int(pub_port <= 0) + int(req_port <= 0)
376 for i in xrange(ports_needed):
377 for i in xrange(ports_needed):
377 sock = socket.socket()
378 sock = socket.socket()
378 sock.bind(('', 0))
379 sock.bind(('', 0))
379 ports.append(sock)
380 ports.append(sock)
380 for i, sock in enumerate(ports):
381 for i, sock in enumerate(ports):
381 port = sock.getsockname()[1]
382 port = sock.getsockname()[1]
382 sock.close()
383 sock.close()
383 ports[i] = port
384 ports[i] = port
384 if xrep_port <= 0:
385 if xrep_port <= 0:
385 xrep_port = ports.pop(0)
386 xrep_port = ports.pop(0)
386 if pub_port <= 0:
387 if pub_port <= 0:
387 pub_port = ports.pop(0)
388 pub_port = ports.pop(0)
388 if req_port <= 0:
389 if req_port <= 0:
389 req_port = ports.pop(0)
390 req_port = ports.pop(0)
390
391
391 # Spawn a kernel.
392 # Spawn a kernel.
392 command = 'from IPython.zmq.kernel import main; main()'
393 command = 'from IPython.zmq.kernel import main; main()'
393 arguments = [ sys.executable, '-c', command, '--xrep', str(xrep_port),
394 arguments = [ sys.executable, '-c', command, '--xrep', str(xrep_port),
394 '--pub', str(pub_port), '--req', str(req_port) ]
395 '--pub', str(pub_port), '--req', str(req_port) ]
395
396
396 if independent:
397 if independent:
397 if sys.platform == 'win32':
398 if sys.platform == 'win32':
398 proc = Popen(['start', '/b'] + arguments, shell=True)
399 proc = Popen(['start', '/b'] + arguments, shell=True)
399 else:
400 else:
400 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
401 proc = Popen(arguments, preexec_fn=lambda: os.setsid())
401
402
402 else:
403 else:
403 proc = Popen(arguments + ['--require-parent'])
404 proc = Popen(arguments + ['--require-parent'])
404
405
405 return proc, xrep_port, pub_port, req_port
406 return proc, xrep_port, pub_port, req_port
406
407
407
408
408 if __name__ == '__main__':
409 if __name__ == '__main__':
409 main()
410 main()
General Comments 0
You need to be logged in to leave comments. Login now